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.management.mbean.ManagedBacklogDebugger;
040import org.apache.camel.management.mbean.ManagedBacklogTracer;
041import org.apache.camel.management.mbean.ManagedCamelContext;
042import org.apache.camel.management.mbean.ManagedCamelHealth;
043import org.apache.camel.management.mbean.ManagedClusterService;
044import org.apache.camel.management.mbean.ManagedComponent;
045import org.apache.camel.management.mbean.ManagedConsumer;
046import org.apache.camel.management.mbean.ManagedDataFormat;
047import org.apache.camel.management.mbean.ManagedEndpoint;
048import org.apache.camel.management.mbean.ManagedErrorHandler;
049import org.apache.camel.management.mbean.ManagedEventNotifier;
050import org.apache.camel.management.mbean.ManagedProcessor;
051import org.apache.camel.management.mbean.ManagedProducer;
052import org.apache.camel.management.mbean.ManagedRoute;
053import org.apache.camel.management.mbean.ManagedRouteController;
054import org.apache.camel.management.mbean.ManagedService;
055import org.apache.camel.management.mbean.ManagedStep;
056import org.apache.camel.management.mbean.ManagedThreadPool;
057import org.apache.camel.management.mbean.ManagedTracer;
058import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier;
059import org.apache.camel.spi.DataFormat;
060import org.apache.camel.spi.EventNotifier;
061import org.apache.camel.spi.ManagementObjectNameStrategy;
062import org.apache.camel.util.InetAddressUtil;
063import org.apache.camel.util.ObjectHelper;
064import org.apache.camel.util.URISupport;
065
066/**
067 * Naming strategy used when registering MBeans.
068 */
069public class DefaultManagementObjectNameStrategy implements ManagementObjectNameStrategy, CamelContextAware {
070    public static final String VALUE_UNKNOWN = "unknown";
071    public static final String KEY_NAME = "name";
072    public static final String KEY_TYPE = "type";
073    public static final String KEY_CONTEXT = "context";
074    public static final String TYPE_CONTEXT = "context";
075    public static final String TYPE_ROUTE_CONTROLLER = "routecontrollers";
076    public static final String TYPE_HEALTH = "health";
077    public static final String TYPE_ENDPOINT = "endpoints";
078    public static final String TYPE_DATAFORMAT = "dataformats";
079    public static final String TYPE_PROCESSOR = "processors";
080    public static final String TYPE_CONSUMER = "consumers";
081    public static final String TYPE_PRODUCER = "producers";
082    public static final String TYPE_ROUTE = "routes";
083    public static final String TYPE_COMPONENT = "components";
084    public static final String TYPE_STEP = "steps";
085    public static final String TYPE_TRACER = "tracer";
086    public static final String TYPE_EVENT_NOTIFIER = "eventnotifiers";
087    public static final String TYPE_ERRORHANDLER = "errorhandlers";
088    public static final String TYPE_THREAD_POOL = "threadpools";
089    public static final String TYPE_SERVICE = "services";
090    public static final String TYPE_HA = "clusterservices";
091
092    protected String domainName;
093    protected String hostName = "localhost";
094    protected CamelContext camelContext;
095
096    public DefaultManagementObjectNameStrategy() {
097        this(null);
098        // default constructor needed for <bean> style configuration
099    }
100
101    public DefaultManagementObjectNameStrategy(String domainName) {
102        this.domainName = domainName != null ? domainName : "org.apache.camel";
103        try {
104            hostName = InetAddressUtil.getLocalHostName();
105        } catch (UnknownHostException ex) {
106            // ignore, use the default "localhost"
107        }
108    }
109
110    @Override
111    public CamelContext getCamelContext() {
112        return camelContext;
113    }
114
115    @Override
116    public void setCamelContext(CamelContext camelContext) {
117        this.camelContext = camelContext;
118    }
119
120    @Override
121    public ObjectName getObjectName(Object managedObject) throws MalformedObjectNameException {
122        if (managedObject == null) {
123            return null;
124        }
125        ObjectName objectName = null;
126        if (managedObject instanceof ManagedCamelContext) {
127            ManagedCamelContext mcc = (ManagedCamelContext) managedObject;
128            objectName = getObjectNameForCamelContext(mcc.getContext());
129        } else if (managedObject instanceof ManagedCamelHealth) {
130            ManagedCamelHealth mch = (ManagedCamelHealth) managedObject;
131            objectName = getObjectNameForCamelHealth(mch.getContext());
132        } else if (managedObject instanceof ManagedRouteController) {
133            ManagedRouteController mrc = (ManagedRouteController) managedObject;
134            objectName = getObjectNameForRouteController(mrc.getContext());
135        } else if (managedObject instanceof ManagedComponent) {
136            ManagedComponent mc = (ManagedComponent) managedObject;
137            objectName = getObjectNameForComponent(mc.getComponent(), mc.getComponentName());
138        } else if (managedObject instanceof ManagedDataFormat) {
139            ManagedDataFormat md = (ManagedDataFormat) managedObject;
140            objectName = getObjectNameForDataFormat(md.getContext(), md.getDataFormat());
141        } else if (managedObject instanceof ManagedEndpoint) {
142            ManagedEndpoint me = (ManagedEndpoint) managedObject;
143            objectName = getObjectNameForEndpoint(me.getEndpoint());
144        } else if (managedObject instanceof Endpoint) {
145            objectName = getObjectNameForEndpoint((Endpoint) managedObject);
146        } else if (managedObject instanceof ManagedRoute) {
147            ManagedRoute mr = (ManagedRoute) managedObject;
148            objectName = getObjectNameForRoute(mr.getRoute());
149        } else if (managedObject instanceof ManagedErrorHandler) {
150            ManagedErrorHandler meh = (ManagedErrorHandler) managedObject;
151            objectName = getObjectNameForErrorHandler(meh.getRoute(), meh.getErrorHandler(), meh.getErrorHandlerBuilder());
152        } else if (managedObject instanceof ManagedStep) {
153            ManagedStep mp = (ManagedStep) managedObject;
154            objectName = getObjectNameForStep(mp.getContext(), mp.getProcessor(), mp.getDefinition());
155        } else if (managedObject instanceof ManagedProcessor) {
156            ManagedProcessor mp = (ManagedProcessor) managedObject;
157            objectName = getObjectNameForProcessor(mp.getContext(), mp.getProcessor(), mp.getDefinition());
158        } else if (managedObject instanceof ManagedConsumer) {
159            ManagedConsumer ms = (ManagedConsumer) managedObject;
160            objectName = getObjectNameForConsumer(ms.getContext(), ms.getConsumer());
161        } else if (managedObject instanceof ManagedProducer) {
162            ManagedProducer ms = (ManagedProducer) managedObject;
163            objectName = getObjectNameForProducer(ms.getContext(), ms.getProducer());
164        } else if (managedObject instanceof ManagedBacklogTracer) {
165            ManagedBacklogTracer mt = (ManagedBacklogTracer) managedObject;
166            objectName = getObjectNameForTracer(mt.getContext(), mt.getBacklogTracer());
167        } else if (managedObject instanceof ManagedBacklogDebugger) {
168            ManagedBacklogDebugger md = (ManagedBacklogDebugger) managedObject;
169            objectName = getObjectNameForTracer(md.getContext(), md.getBacklogDebugger());
170        } else if (managedObject instanceof ManagedEventNotifier) {
171            ManagedEventNotifier men = (ManagedEventNotifier) managedObject;
172            objectName = getObjectNameForEventNotifier(men.getContext(), men.getEventNotifier());
173        } else if (managedObject instanceof ManagedTracer) {
174            ManagedTracer mt = (ManagedTracer) managedObject;
175            objectName = getObjectNameForTracer(mt.getContext(), mt.getTracer());
176        } else if (managedObject instanceof ManagedThreadPool) {
177            ManagedThreadPool mes = (ManagedThreadPool) managedObject;
178            objectName = getObjectNameForThreadPool(mes.getContext(), mes.getThreadPool(), mes.getId(), mes.getSourceId());
179        } else if (managedObject instanceof ManagedClusterService) {
180            ManagedClusterService mcs = (ManagedClusterService) managedObject;
181            objectName = getObjectNameForClusterService(mcs.getContext(), mcs.getService());
182        } else if (managedObject instanceof ManagedService) {
183            // check for managed service should be last
184            ManagedService ms = (ManagedService) managedObject;
185            // skip endpoints as they are already managed
186            if (ms.getService() instanceof Endpoint) {
187                return null;
188            }
189            objectName = getObjectNameForService(ms.getContext(), ms.getService());
190        }
191
192        return objectName;
193    }
194
195    @Override
196    public ObjectName getObjectNameForCamelContext(String managementName, String name) throws MalformedObjectNameException {
197        StringBuilder buffer = new StringBuilder();
198        buffer.append(domainName).append(":");
199        buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(",");
200        buffer.append(KEY_TYPE + "=" + TYPE_CONTEXT + ",");
201        buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
202        return createObjectName(buffer);
203    }
204
205    @Override
206    public ObjectName getObjectNameForCamelContext(CamelContext context) throws MalformedObjectNameException {
207        // prefer to use the given management name if previously assigned
208        String managementName = context.getManagementName();
209        if (managementName == null) {
210            managementName = context.getManagementNameStrategy().getName();
211        }
212        String name = context.getName();
213        return getObjectNameForCamelContext(managementName, name);
214    }
215
216    @Override
217    public ObjectName getObjectNameForCamelHealth(CamelContext context) throws MalformedObjectNameException {
218        // prefer to use the given management name if previously assigned
219        String managementName = context.getManagementName();
220        if (managementName == null) {
221            managementName = context.getManagementNameStrategy().getName();
222        }
223
224        StringBuilder buffer = new StringBuilder();
225        buffer.append(domainName).append(":");
226        buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(",");
227        buffer.append(KEY_TYPE + "=" + TYPE_HEALTH + ",");
228        buffer.append(KEY_NAME + "=").append(ObjectName.quote(context.getName()));
229
230        return createObjectName(buffer);
231    }
232
233    @Override
234    public ObjectName getObjectNameForRouteController(CamelContext context) throws MalformedObjectNameException {
235        // prefer to use the given management name if previously assigned
236        String managementName = context.getManagementName();
237        if (managementName == null) {
238            managementName = context.getManagementNameStrategy().getName();
239        }
240
241        StringBuilder buffer = new StringBuilder();
242        buffer.append(domainName).append(":");
243        buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(",");
244        buffer.append(KEY_TYPE + "=" + TYPE_ROUTE_CONTROLLER + ",");
245        buffer.append(KEY_NAME + "=").append(ObjectName.quote(context.getName()));
246
247        return createObjectName(buffer);
248    }
249
250    @Override
251    public ObjectName getObjectNameForEndpoint(Endpoint endpoint) throws MalformedObjectNameException {
252        StringBuilder buffer = new StringBuilder();
253        buffer.append(domainName).append(":");
254        buffer.append(KEY_CONTEXT + "=").append(getContextId(endpoint.getCamelContext())).append(",");
255        buffer.append(KEY_TYPE + "=" + TYPE_ENDPOINT + ",");
256        buffer.append(KEY_NAME + "=").append(ObjectName.quote(getEndpointId(endpoint)));
257        return createObjectName(buffer);
258    }
259
260    @Override
261    public ObjectName getObjectNameForDataFormat(CamelContext context, DataFormat dataFormat) throws MalformedObjectNameException {
262        StringBuilder buffer = new StringBuilder();
263        buffer.append(domainName).append(":");
264        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
265        buffer.append(KEY_TYPE + "=" + TYPE_DATAFORMAT + ",");
266        buffer.append(KEY_NAME + "=").append(dataFormat.getClass().getSimpleName());
267        if (!(dataFormat instanceof StaticService)) {
268            buffer.append("(").append(ObjectHelper.getIdentityHashCode(dataFormat)).append(")");
269        }
270        return createObjectName(buffer);
271    }
272
273    @Override
274    public ObjectName getObjectNameForComponent(Component component, String name) throws MalformedObjectNameException {
275        StringBuilder buffer = new StringBuilder();
276        buffer.append(domainName).append(":");
277        buffer.append(KEY_CONTEXT + "=").append(getContextId(component.getCamelContext())).append(",");
278        buffer.append(KEY_TYPE + "=" + TYPE_COMPONENT + ",");
279        buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
280        return createObjectName(buffer);
281    }
282
283    @Override
284    public ObjectName getObjectNameForProcessor(CamelContext context, Processor processor, NamedNode definition) 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 + "=").append(TYPE_PROCESSOR).append(",");
289        buffer.append(KEY_NAME + "=").append(ObjectName.quote(definition.getId()));
290        return createObjectName(buffer);
291    }
292
293    @Override
294    public ObjectName getObjectNameForStep(CamelContext context, Processor processor, NamedNode definition) throws MalformedObjectNameException {
295        StringBuilder buffer = new StringBuilder();
296        buffer.append(domainName).append(":");
297        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
298        buffer.append(KEY_TYPE + "=").append(TYPE_STEP).append(",");
299        buffer.append(KEY_NAME + "=").append(ObjectName.quote(definition.getId()));
300        return createObjectName(buffer);
301    }
302
303    @Override
304    public ObjectName getObjectNameForErrorHandler(Route route, Processor errorHandler, ErrorHandlerFactory builder) throws MalformedObjectNameException {
305        StringBuilder buffer = new StringBuilder();
306        buffer.append(domainName).append(":");
307        buffer.append(KEY_CONTEXT + "=").append(getContextId(route.getCamelContext())).append(",");
308        buffer.append(KEY_TYPE + "=").append(TYPE_ERRORHANDLER + ",");
309
310        // we want to only register one instance of the various error handler types and thus do some lookup
311        // if its a ErrorHandlerBuildRef. We need a bit of work to do that as there are potential indirection.
312        String ref = null;
313        if (builder instanceof ErrorHandlerBuilderRef) {
314            ErrorHandlerBuilderRef builderRef = (ErrorHandlerBuilderRef) builder;
315
316            // it has not then its an indirection and we should do some work to lookup the real builder
317            ref = builderRef.getRef();
318            ErrorHandlerFactory refBuilder = ErrorHandlerReifier.lookupErrorHandlerFactory(route, builderRef.getRef(), false);
319            if (refBuilder != null) {
320                builder = refBuilder;
321            }
322
323            // must do a 2nd lookup in case this is also a reference
324            // (this happens with spring DSL using errorHandlerRef on <route> as it gets a bit
325            // complex with indirections for error handler references
326            if (builder instanceof ErrorHandlerBuilderRef) {
327                builderRef = (ErrorHandlerBuilderRef) builder;
328                // does it refer to a non default error handler then do a 2nd lookup
329                if (!builderRef.getRef().equals(ErrorHandlerBuilderRef.DEFAULT_ERROR_HANDLER_BUILDER)) {
330                    refBuilder = ErrorHandlerReifier.lookupErrorHandlerFactory(route, builderRef.getRef(), false);
331                    if (refBuilder != null) {
332                        ref = builderRef.getRef();
333                        builder = refBuilder;
334                    }
335                }
336            }
337        }
338
339        if (ref != null) {
340            String name = builder.getClass().getSimpleName() + "(ref:" + ref + ")";
341            buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
342        } else {
343            // create a name based on its instance
344            buffer.append(KEY_NAME + "=")
345                .append(builder.getClass().getSimpleName())
346                .append("(").append(ObjectHelper.getIdentityHashCode(builder)).append(")");
347        }
348
349        return createObjectName(buffer);
350    }
351
352    @Override
353    public ObjectName getObjectNameForConsumer(CamelContext context, Consumer consumer) throws MalformedObjectNameException {
354        StringBuilder buffer = new StringBuilder();
355        buffer.append(domainName).append(":");
356        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
357        buffer.append(KEY_TYPE + "=").append(TYPE_CONSUMER).append(",");
358
359        String name = consumer.getClass().getSimpleName();
360        if (ObjectHelper.isEmpty(name)) {
361            name = "Consumer";
362        }
363        buffer.append(KEY_NAME + "=")
364            .append(name)
365            .append("(").append(ObjectHelper.getIdentityHashCode(consumer)).append(")");
366        return createObjectName(buffer);
367    }
368
369    @Override
370    public ObjectName getObjectNameForProducer(CamelContext context, Producer producer) throws MalformedObjectNameException {
371        StringBuilder buffer = new StringBuilder();
372        buffer.append(domainName).append(":");
373        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
374        buffer.append(KEY_TYPE + "=").append(TYPE_PRODUCER).append(",");
375
376        String name = producer.getClass().getSimpleName();
377        if (ObjectHelper.isEmpty(name)) {
378            name = "Producer";
379        }
380        buffer.append(KEY_NAME + "=")
381            .append(name)
382            .append("(").append(ObjectHelper.getIdentityHashCode(producer)).append(")");
383        return createObjectName(buffer);
384    }
385
386    @Override
387    public ObjectName getObjectNameForTracer(CamelContext context, Service tracer) throws MalformedObjectNameException {
388        // use the simple name of the class as the mbean name (eg Tracer, BacklogTracer, BacklogDebugger)
389        String name = tracer.getClass().getSimpleName();
390
391        StringBuilder buffer = new StringBuilder();
392        buffer.append(domainName).append(":");
393        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
394        buffer.append(KEY_TYPE + "=" + TYPE_TRACER + ",");
395        buffer.append(KEY_NAME + "=").append(name);
396        return createObjectName(buffer);
397    }
398
399    @Override
400    public ObjectName getObjectNameForEventNotifier(CamelContext context, EventNotifier eventNotifier) throws MalformedObjectNameException {
401        StringBuilder buffer = new StringBuilder();
402        buffer.append(domainName).append(":");
403        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
404        buffer.append(KEY_TYPE + "=" + TYPE_EVENT_NOTIFIER + ",");
405
406        if (eventNotifier instanceof JmxNotificationEventNotifier) {
407            // JMX notifier shall have an easy to use name
408            buffer.append(KEY_NAME + "=").append("JmxEventNotifier");
409        } else {
410            // others can be per instance
411            buffer.append(KEY_NAME + "=")
412                .append("EventNotifier")
413                .append("(").append(ObjectHelper.getIdentityHashCode(eventNotifier)).append(")");
414        }
415        return createObjectName(buffer);
416    }
417
418    @Override
419    public ObjectName getObjectNameForRoute(org.apache.camel.Route route) throws MalformedObjectNameException {
420        Endpoint ep = route.getEndpoint();
421        String id = route.getId();
422
423        StringBuilder buffer = new StringBuilder();
424        buffer.append(domainName).append(":");
425        buffer.append(KEY_CONTEXT + "=").append(getContextId(ep.getCamelContext())).append(",");
426        buffer.append(KEY_TYPE + "=" + TYPE_ROUTE + ",");
427        buffer.append(KEY_NAME + "=").append(ObjectName.quote(id));
428        return createObjectName(buffer);
429    }
430
431    @Override
432    public ObjectName getObjectNameForService(CamelContext context, Service service) throws MalformedObjectNameException {
433        StringBuilder buffer = new StringBuilder();
434        buffer.append(domainName).append(":");
435        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
436        buffer.append(KEY_TYPE + "=" + TYPE_SERVICE + ",");
437        buffer.append(KEY_NAME + "=").append(service.getClass().getSimpleName());
438        if (!(service instanceof StaticService)) {
439            buffer.append("(").append(ObjectHelper.getIdentityHashCode(service)).append(")");
440        }
441        return createObjectName(buffer);
442    }
443
444    @Override
445    public ObjectName getObjectNameForClusterService(CamelContext context, CamelClusterService service) throws MalformedObjectNameException {
446        StringBuilder buffer = new StringBuilder();
447        buffer.append(domainName).append(":");
448        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
449        buffer.append(KEY_TYPE + "=" + TYPE_HA + ",");
450        buffer.append(KEY_NAME + "=").append(service.getClass().getSimpleName());
451        if (!(service instanceof StaticService)) {
452            buffer.append("(").append(ObjectHelper.getIdentityHashCode(service)).append(")");
453        }
454        return createObjectName(buffer);
455    }
456
457    @Override
458    public ObjectName getObjectNameForThreadPool(CamelContext context, ThreadPoolExecutor threadPool, String id, String sourceId) throws MalformedObjectNameException {
459        StringBuilder buffer = new StringBuilder();
460        buffer.append(domainName).append(":");
461        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
462        buffer.append(KEY_TYPE + "=" + TYPE_THREAD_POOL + ",");
463
464        String name = id;
465        if (sourceId != null) {
466            // provide source id if we know it, this helps end user to know where the pool is used
467            name = name + "(" + sourceId + ")";
468        }
469        buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
470        return createObjectName(buffer);
471    }
472
473    public String getDomainName() {
474        return domainName;
475    }
476
477    public void setDomainName(String domainName) {
478        this.domainName = domainName;
479    }
480
481    public String getHostName() {
482        return hostName;
483    }
484
485    public void setHostName(String hostName) {
486        this.hostName = hostName;
487    }
488
489    protected String getContextId(CamelContext context) {
490        if (context == null) {
491            return getContextId(VALUE_UNKNOWN);
492        } else {
493            String name = context.getManagementName() != null ? context.getManagementName() : context.getName();
494            return getContextId(name);
495        }
496    }
497
498    protected String getContextId(String name) {
499        boolean includeHostName = camelContext != null && camelContext.getManagementStrategy().getManagementAgent().getIncludeHostName();
500        if (includeHostName) {
501            return hostName + "/" + (name != null ? name : VALUE_UNKNOWN);
502        } else {
503            return name != null ? name : VALUE_UNKNOWN;
504        }
505    }
506
507    protected String getEndpointId(Endpoint ep) {
508        String answer = doGetEndpointId(ep);
509        boolean sanitize = camelContext != null && camelContext.getManagementStrategy().getManagementAgent().getMask();
510        if (sanitize) {
511            // use xxxxxx as replacements as * has to be quoted for MBean names
512            answer = URISupport.sanitizeUri(answer);
513        }
514        return answer;
515    }
516
517    private String doGetEndpointId(Endpoint ep) {
518        if (ep.isSingleton()) {
519            return ep.getEndpointKey();
520        } else {
521            // non singleton then add hashcoded id
522            String uri = ep.getEndpointKey();
523            int pos = uri.indexOf('?');
524            String id = (pos == -1) ? uri : uri.substring(0, pos);
525            id += "?id=" + ObjectHelper.getIdentityHashCode(ep);
526            return id;
527        }
528    }
529
530    /**
531     * Factory method to create an ObjectName escaping any required characters
532     */
533    protected ObjectName createObjectName(StringBuilder buffer) throws MalformedObjectNameException {
534        String text = buffer.toString();
535        try {
536            return new ObjectName(text);
537        } catch (MalformedObjectNameException e) {
538            throw new MalformedObjectNameException("Could not create ObjectName from: " + text + ". Reason: " + e);
539        }
540    }
541}