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.NamedNode;
031import org.apache.camel.Processor;
032import org.apache.camel.Producer;
033import org.apache.camel.Service;
034import org.apache.camel.StaticService;
035import org.apache.camel.cluster.CamelClusterService;
036import org.apache.camel.management.mbean.ManagedBacklogDebugger;
037import org.apache.camel.management.mbean.ManagedBacklogTracer;
038import org.apache.camel.management.mbean.ManagedCamelContext;
039import org.apache.camel.management.mbean.ManagedCamelHealth;
040import org.apache.camel.management.mbean.ManagedClusterService;
041import org.apache.camel.management.mbean.ManagedComponent;
042import org.apache.camel.management.mbean.ManagedConsumer;
043import org.apache.camel.management.mbean.ManagedDataFormat;
044import org.apache.camel.management.mbean.ManagedDumpRouteStrategy;
045import org.apache.camel.management.mbean.ManagedEndpoint;
046import org.apache.camel.management.mbean.ManagedEventNotifier;
047import org.apache.camel.management.mbean.ManagedProcessor;
048import org.apache.camel.management.mbean.ManagedProducer;
049import org.apache.camel.management.mbean.ManagedRoute;
050import org.apache.camel.management.mbean.ManagedRouteController;
051import org.apache.camel.management.mbean.ManagedService;
052import org.apache.camel.management.mbean.ManagedStep;
053import org.apache.camel.management.mbean.ManagedSupervisingRouteController;
054import org.apache.camel.management.mbean.ManagedThreadPool;
055import org.apache.camel.management.mbean.ManagedTracer;
056import org.apache.camel.spi.DataFormat;
057import org.apache.camel.spi.EventNotifier;
058import org.apache.camel.spi.ManagementObjectNameStrategy;
059import org.apache.camel.spi.RouteController;
060import org.apache.camel.util.InetAddressUtil;
061import org.apache.camel.util.ObjectHelper;
062import org.apache.camel.util.StringHelper;
063import org.apache.camel.util.URISupport;
064
065/**
066 * Naming strategy used when registering MBeans.
067 */
068public class DefaultManagementObjectNameStrategy implements ManagementObjectNameStrategy, CamelContextAware {
069    public static final String VALUE_UNKNOWN = "unknown";
070    public static final String KEY_NAME = "name";
071    public static final String KEY_TYPE = "type";
072    public static final String KEY_CONTEXT = "context";
073    public static final String TYPE_CONTEXT = "context";
074    public static final String TYPE_HEALTH = "health";
075    public static final String TYPE_ENDPOINT = "endpoints";
076    public static final String TYPE_DATAFORMAT = "dataformats";
077    public static final String TYPE_PROCESSOR = "processors";
078    public static final String TYPE_CONSUMER = "consumers";
079    public static final String TYPE_PRODUCER = "producers";
080    public static final String TYPE_ROUTE = "routes";
081    public static final String TYPE_COMPONENT = "components";
082    public static final String TYPE_STEP = "steps";
083    public static final String TYPE_TRACER = "tracer";
084    public static final String TYPE_EVENT_NOTIFIER = "eventnotifiers";
085    public static final String TYPE_THREAD_POOL = "threadpools";
086    public static final String TYPE_SERVICE = "services";
087    public static final String TYPE_HA = "clusterservices";
088
089    protected String domainName;
090    protected String hostName = "localhost";
091    protected CamelContext camelContext;
092
093    public DefaultManagementObjectNameStrategy() {
094        this(null);
095        // default constructor needed for <bean> style configuration
096    }
097
098    public DefaultManagementObjectNameStrategy(String domainName) {
099        this.domainName = domainName != null ? domainName : "org.apache.camel";
100        try {
101            hostName = InetAddressUtil.getLocalHostName();
102        } catch (UnknownHostException ex) {
103            // ignore, use the default "localhost"
104        }
105    }
106
107    @Override
108    public CamelContext getCamelContext() {
109        return camelContext;
110    }
111
112    @Override
113    public void setCamelContext(CamelContext camelContext) {
114        this.camelContext = camelContext;
115    }
116
117    @Override
118    public ObjectName getObjectName(Object managedObject) throws MalformedObjectNameException {
119        if (managedObject == null) {
120            return null;
121        }
122        ObjectName objectName = null;
123        if (managedObject instanceof ManagedCamelContext) {
124            ManagedCamelContext mcc = (ManagedCamelContext) managedObject;
125            objectName = getObjectNameForCamelContext(mcc.getContext());
126        } else if (managedObject instanceof ManagedCamelHealth) {
127            ManagedCamelHealth mch = (ManagedCamelHealth) managedObject;
128            objectName = getObjectNameForCamelHealth(mch.getContext());
129        } else if (managedObject instanceof ManagedRouteController) {
130            ManagedRouteController mrc = (ManagedRouteController) managedObject;
131            objectName = getObjectNameForRouteController(mrc.getContext(), mrc.getRouteController());
132        } else if (managedObject instanceof ManagedSupervisingRouteController) {
133            ManagedSupervisingRouteController mrc = (ManagedSupervisingRouteController) managedObject;
134            objectName = getObjectNameForRouteController(mrc.getContext(), mrc.getRouteController());
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 ManagedStep) {
150            ManagedStep mp = (ManagedStep) managedObject;
151            objectName = getObjectNameForStep(mp.getContext(), mp.getProcessor(), mp.getDefinition());
152        } else if (managedObject instanceof ManagedProcessor) {
153            ManagedProcessor mp = (ManagedProcessor) managedObject;
154            objectName = getObjectNameForProcessor(mp.getContext(), mp.getProcessor(), mp.getDefinition());
155        } else if (managedObject instanceof ManagedConsumer) {
156            ManagedConsumer ms = (ManagedConsumer) managedObject;
157            objectName = getObjectNameForConsumer(ms.getContext(), ms.getConsumer());
158        } else if (managedObject instanceof ManagedProducer) {
159            ManagedProducer ms = (ManagedProducer) managedObject;
160            objectName = getObjectNameForProducer(ms.getContext(), ms.getProducer());
161        } else if (managedObject instanceof ManagedBacklogTracer) {
162            ManagedBacklogTracer mt = (ManagedBacklogTracer) managedObject;
163            objectName = getObjectNameForTracer(mt.getContext(), mt.getBacklogTracer());
164        } else if (managedObject instanceof ManagedBacklogDebugger) {
165            ManagedBacklogDebugger md = (ManagedBacklogDebugger) managedObject;
166            objectName = getObjectNameForTracer(md.getContext(), md.getBacklogDebugger());
167        } else if (managedObject instanceof ManagedDumpRouteStrategy) {
168            ManagedDumpRouteStrategy md = (ManagedDumpRouteStrategy) managedObject;
169            objectName = getObjectNameForService(md.getContext(), md.getDumpRoutesStrategy());
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("DefaultHealthCheck");
229
230        return createObjectName(buffer);
231    }
232
233    @Override
234    public ObjectName getObjectNameForRouteController(CamelContext context, RouteController routeController)
235            throws MalformedObjectNameException {
236        // prefer to use the given management name if previously assigned
237        String managementName = context.getManagementName();
238        if (managementName == null) {
239            managementName = context.getManagementNameStrategy().getName();
240        }
241
242        StringBuilder buffer = new StringBuilder();
243        buffer.append(domainName).append(":");
244        buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(",");
245        buffer.append(KEY_TYPE + "=" + TYPE_SERVICE + ",");
246        buffer.append(KEY_NAME + "=").append(routeController.getClass().getSimpleName());
247
248        return createObjectName(buffer);
249    }
250
251    @Override
252    public ObjectName getObjectNameForEndpoint(Endpoint endpoint) throws MalformedObjectNameException {
253        StringBuilder buffer = new StringBuilder();
254        buffer.append(domainName).append(":");
255        buffer.append(KEY_CONTEXT + "=").append(getContextId(endpoint.getCamelContext())).append(",");
256        buffer.append(KEY_TYPE + "=" + TYPE_ENDPOINT + ",");
257        buffer.append(KEY_NAME + "=").append(ObjectName.quote(getEndpointId(endpoint)));
258        return createObjectName(buffer);
259    }
260
261    @Override
262    public ObjectName getObjectNameForDataFormat(CamelContext context, DataFormat dataFormat)
263            throws MalformedObjectNameException {
264        StringBuilder buffer = new StringBuilder();
265        buffer.append(domainName).append(":");
266        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
267        buffer.append(KEY_TYPE + "=" + TYPE_DATAFORMAT + ",");
268        buffer.append(KEY_NAME + "=").append(dataFormat.getClass().getSimpleName());
269        if (!(dataFormat instanceof StaticService)) {
270            buffer.append("(").append(ObjectHelper.getIdentityHashCode(dataFormat)).append(")");
271        }
272        return createObjectName(buffer);
273    }
274
275    @Override
276    public ObjectName getObjectNameForComponent(Component component, String name) throws MalformedObjectNameException {
277        StringBuilder buffer = new StringBuilder();
278        buffer.append(domainName).append(":");
279        buffer.append(KEY_CONTEXT + "=").append(getContextId(component.getCamelContext())).append(",");
280        buffer.append(KEY_TYPE + "=" + TYPE_COMPONENT + ",");
281        buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
282        return createObjectName(buffer);
283    }
284
285    @Override
286    public ObjectName getObjectNameForProcessor(CamelContext context, Processor processor, NamedNode definition)
287            throws MalformedObjectNameException {
288        StringBuilder buffer = new StringBuilder();
289        buffer.append(domainName).append(":");
290        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
291        buffer.append(KEY_TYPE + "=").append(TYPE_PROCESSOR).append(",");
292        String id = definition.getId();
293        String prefix = definition.getNodePrefixId();
294        if (prefix != null) {
295            id = prefix + id;
296        }
297        buffer.append(KEY_NAME + "=").append(ObjectName.quote(id));
298        return createObjectName(buffer);
299    }
300
301    @Override
302    public ObjectName getObjectNameForStep(CamelContext context, Processor processor, NamedNode definition)
303            throws MalformedObjectNameException {
304        StringBuilder buffer = new StringBuilder();
305        buffer.append(domainName).append(":");
306        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
307        buffer.append(KEY_TYPE + "=").append(TYPE_STEP).append(",");
308        String id = definition.getId();
309        String prefix = definition.getNodePrefixId();
310        if (prefix != null) {
311            id = prefix + id;
312        }
313        buffer.append(KEY_NAME + "=").append(ObjectName.quote(id));
314        return createObjectName(buffer);
315    }
316
317    @Override
318    public ObjectName getObjectNameForConsumer(CamelContext context, Consumer consumer) throws MalformedObjectNameException {
319        StringBuilder buffer = new StringBuilder();
320        buffer.append(domainName).append(":");
321        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
322        buffer.append(KEY_TYPE + "=").append(TYPE_CONSUMER).append(",");
323
324        String name = consumer.getClass().getSimpleName();
325        if (ObjectHelper.isEmpty(name)) {
326            name = "Consumer";
327        }
328        buffer.append(KEY_NAME + "=")
329                .append(name)
330                .append("(").append(ObjectHelper.getIdentityHashCode(consumer)).append(")");
331        return createObjectName(buffer);
332    }
333
334    @Override
335    public ObjectName getObjectNameForProducer(CamelContext context, Producer producer) throws MalformedObjectNameException {
336        StringBuilder buffer = new StringBuilder();
337        buffer.append(domainName).append(":");
338        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
339        buffer.append(KEY_TYPE + "=").append(TYPE_PRODUCER).append(",");
340
341        String name = producer.getClass().getSimpleName();
342        if (ObjectHelper.isEmpty(name)) {
343            name = "Producer";
344        }
345        buffer.append(KEY_NAME + "=")
346                .append(name)
347                .append("(").append(ObjectHelper.getIdentityHashCode(producer)).append(")");
348        return createObjectName(buffer);
349    }
350
351    @Override
352    public ObjectName getObjectNameForTracer(CamelContext context, Service tracer) throws MalformedObjectNameException {
353        // use the simple name of the class as the mbean name (eg Tracer, BacklogTracer, BacklogDebugger)
354        String name = tracer.getClass().getSimpleName();
355        // backwards compatible names
356        if ("DefaultBacklogDebugger".equals(name)) {
357            name = "BacklogDebugger";
358        } else if ("DefaultBacklogTracer".equals(name)) {
359            name = "BacklogTracer";
360        }
361
362        StringBuilder buffer = new StringBuilder();
363        buffer.append(domainName).append(":");
364        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
365        buffer.append(KEY_TYPE + "=" + TYPE_TRACER + ",");
366        buffer.append(KEY_NAME + "=").append(name);
367        return createObjectName(buffer);
368    }
369
370    @Override
371    public ObjectName getObjectNameForEventNotifier(CamelContext context, EventNotifier eventNotifier)
372            throws MalformedObjectNameException {
373        StringBuilder buffer = new StringBuilder();
374        buffer.append(domainName).append(":");
375        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
376        buffer.append(KEY_TYPE + "=" + TYPE_EVENT_NOTIFIER + ",");
377
378        if (eventNotifier instanceof JmxNotificationEventNotifier) {
379            // JMX notifier shall have an easy to use name
380            buffer.append(KEY_NAME + "=").append("JmxEventNotifier");
381        } else {
382            // others can be per instance
383            buffer.append(KEY_NAME + "=")
384                    .append("EventNotifier")
385                    .append("(").append(ObjectHelper.getIdentityHashCode(eventNotifier)).append(")");
386        }
387        return createObjectName(buffer);
388    }
389
390    @Override
391    public ObjectName getObjectNameForRoute(org.apache.camel.Route route) throws MalformedObjectNameException {
392        StringBuilder buffer = new StringBuilder();
393        buffer.append(domainName).append(":");
394        buffer.append(KEY_CONTEXT + "=").append(getContextId(route.getCamelContext())).append(",");
395        buffer.append(KEY_TYPE + "=" + TYPE_ROUTE + ",");
396        buffer.append(KEY_NAME + "=").append(ObjectName.quote(route.getId()));
397        return createObjectName(buffer);
398    }
399
400    @Override
401    public ObjectName getObjectNameForService(CamelContext context, Service service) throws MalformedObjectNameException {
402        StringBuilder buffer = new StringBuilder();
403        buffer.append(domainName).append(":");
404        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
405        buffer.append(KEY_TYPE + "=" + TYPE_SERVICE + ",");
406        buffer.append(KEY_NAME + "=").append(service.getClass().getSimpleName());
407        if (!(service instanceof StaticService)) {
408            buffer.append("(").append(ObjectHelper.getIdentityHashCode(service)).append(")");
409        }
410        return createObjectName(buffer);
411    }
412
413    @Override
414    public ObjectName getObjectNameForClusterService(CamelContext context, CamelClusterService service)
415            throws MalformedObjectNameException {
416        StringBuilder buffer = new StringBuilder();
417        buffer.append(domainName).append(":");
418        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
419        buffer.append(KEY_TYPE + "=" + TYPE_HA + ",");
420        buffer.append(KEY_NAME + "=").append(service.getClass().getSimpleName());
421        if (!(service instanceof StaticService)) {
422            buffer.append("(").append(ObjectHelper.getIdentityHashCode(service)).append(")");
423        }
424        return createObjectName(buffer);
425    }
426
427    @Override
428    public ObjectName getObjectNameForThreadPool(
429            CamelContext context, ThreadPoolExecutor threadPool, String id, String sourceId)
430            throws MalformedObjectNameException {
431        StringBuilder buffer = new StringBuilder();
432        buffer.append(domainName).append(":");
433        buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
434        buffer.append(KEY_TYPE + "=" + TYPE_THREAD_POOL + ",");
435
436        String name = id;
437        if (sourceId != null) {
438            // provide source id if we know it, this helps end user to know where the pool is used
439            name = name + "(" + sourceId + ")";
440        }
441        buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
442        return createObjectName(buffer);
443    }
444
445    public String getDomainName() {
446        return domainName;
447    }
448
449    public void setDomainName(String domainName) {
450        this.domainName = domainName;
451    }
452
453    public String getHostName() {
454        return hostName;
455    }
456
457    public void setHostName(String hostName) {
458        this.hostName = hostName;
459    }
460
461    protected String getContextId(CamelContext context) {
462        if (context == null) {
463            return getContextId(VALUE_UNKNOWN);
464        } else {
465            String name = context.getManagementName() != null ? context.getManagementName() : context.getName();
466            return getContextId(name);
467        }
468    }
469
470    protected String getContextId(String name) {
471        boolean includeHostName
472                = camelContext != null && camelContext.getManagementStrategy().getManagementAgent().getIncludeHostName();
473        if (includeHostName) {
474            return hostName + "/" + (name != null ? name : VALUE_UNKNOWN);
475        } else {
476            return name != null ? name : VALUE_UNKNOWN;
477        }
478    }
479
480    protected String getEndpointId(Endpoint ep) {
481        String answer = doGetEndpointId(ep);
482        boolean sanitize = camelContext != null && camelContext.getManagementStrategy().getManagementAgent().getMask();
483        if (sanitize) {
484            // use xxxxxx as replacements as * has to be quoted for MBean names
485            answer = URISupport.sanitizeUri(answer);
486        }
487        return answer;
488    }
489
490    private String doGetEndpointId(Endpoint ep) {
491        if (ep.isSingleton()) {
492            return ep.getEndpointKey();
493        } else {
494            // non singleton then add hashcoded id
495            String uri = ep.getEndpointKey();
496            String id = StringHelper.before(uri, "?", uri);
497            id += "?id=" + ObjectHelper.getIdentityHashCode(ep);
498            return id;
499        }
500    }
501
502    /**
503     * Factory method to create an ObjectName escaping any required characters
504     */
505    protected ObjectName createObjectName(StringBuilder buffer) throws MalformedObjectNameException {
506        String text = buffer.toString();
507        try {
508            return new ObjectName(text);
509        } catch (MalformedObjectNameException e) {
510            throw new MalformedObjectNameException("Could not create ObjectName from: " + text + ". Reason: " + e);
511        }
512    }
513}