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