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