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