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    
063        protected String domainName;
064        protected String hostName = "localhost";
065    
066        public DefaultManagementNamingStrategy() {
067            this("org.apache.camel");
068        }
069    
070        public DefaultManagementNamingStrategy(String domainName) {
071            if (domainName != null) {
072                this.domainName = domainName;
073            }
074            try {
075                hostName = InetAddressUtil.getLocalHostName();
076            } catch (UnknownHostException ex) {
077                // ignore, use the default "localhost"
078            }
079        }
080    
081        public ObjectName getObjectNameForCamelContext(String managementName, String name) throws MalformedObjectNameException {
082            StringBuilder buffer = new StringBuilder();
083            buffer.append(domainName).append(":");
084            buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(",");
085            buffer.append(KEY_TYPE + "=" + TYPE_CONTEXT + ",");
086            buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
087            return createObjectName(buffer);
088        }
089    
090        public ObjectName getObjectNameForCamelContext(CamelContext context) throws MalformedObjectNameException {
091            // prefer to use the given management name if previously assigned
092            String managementName = context.getManagementName();
093            if (managementName == null) {
094                managementName = context.getManagementNameStrategy().getName();
095            }
096            String name = context.getName();
097            return getObjectNameForCamelContext(managementName, name);
098        }
099    
100        public ObjectName getObjectNameForEndpoint(Endpoint endpoint) throws MalformedObjectNameException {
101            StringBuilder buffer = new StringBuilder();
102            buffer.append(domainName).append(":");
103            buffer.append(KEY_CONTEXT + "=").append(getContextId(endpoint.getCamelContext())).append(",");
104            buffer.append(KEY_TYPE + "=" + TYPE_ENDPOINT + ",");
105            buffer.append(KEY_NAME + "=").append(ObjectName.quote(getEndpointId(endpoint)));
106            return createObjectName(buffer);
107        }
108    
109        public ObjectName getObjectNameForComponent(Component component, String name) throws MalformedObjectNameException {
110            StringBuilder buffer = new StringBuilder();
111            buffer.append(domainName).append(":");
112            buffer.append(KEY_CONTEXT + "=").append(getContextId(component.getCamelContext())).append(",");
113            buffer.append(KEY_TYPE + "=" + TYPE_COMPONENT + ",");
114            buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
115            return createObjectName(buffer);
116        }
117    
118        public ObjectName getObjectNameForProcessor(CamelContext context, Processor processor, ProcessorDefinition<?> definition) throws MalformedObjectNameException {
119            StringBuilder buffer = new StringBuilder();
120            buffer.append(domainName).append(":");
121            buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
122            buffer.append(KEY_TYPE + "=").append(TYPE_PROCESSOR).append(",");
123            buffer.append(KEY_NAME + "=").append(ObjectName.quote(definition.getId()));
124            return createObjectName(buffer);
125        }
126    
127        public ObjectName getObjectNameForErrorHandler(RouteContext routeContext, Processor errorHandler, ErrorHandlerFactory builder) throws MalformedObjectNameException {
128            StringBuilder buffer = new StringBuilder();
129            buffer.append(domainName + ":" + KEY_CONTEXT + "=" + getContextId(routeContext.getCamelContext()) + ","
130                          + KEY_TYPE + "=" +  TYPE_ERRORHANDLER + ",");
131    
132            // we want to only register one instance of the various error handler types and thus do some lookup
133            // if its a ErrorHandlerBuildRef. We need a bit of work to do that as there are potential indirection.
134            String ref = null;
135            if (builder instanceof ErrorHandlerBuilderRef) {
136                ErrorHandlerBuilderRef builderRef = (ErrorHandlerBuilderRef) builder;
137    
138                // it has not then its an indirection and we should do some work to lookup the real builder
139                ref = builderRef.getRef();
140                builder = ErrorHandlerBuilderRef.lookupErrorHandlerBuilder(routeContext, builderRef.getRef());
141    
142                // must do a 2nd lookup in case this is also a reference
143                // (this happens with spring DSL using errorHandlerRef on <route> as it gets a bit
144                // complex with indirections for error handler references
145                if (builder instanceof ErrorHandlerBuilderRef) {
146                    builderRef = (ErrorHandlerBuilderRef) builder;
147                    // does it refer to a non default error handler then do a 2nd lookup
148                    if (!builderRef.getRef().equals(ErrorHandlerBuilderRef.DEFAULT_ERROR_HANDLER_BUILDER)) {
149                        builder = ErrorHandlerBuilderRef.lookupErrorHandlerBuilder(routeContext, builderRef.getRef());
150                        ref = builderRef.getRef();
151                    }
152                }
153            }
154    
155            if (ref != null) {
156                String name = builder.getClass().getSimpleName() + "(ref:" + ref + ")";
157                buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
158            } else {
159                // create a name based on its instance
160                buffer.append(KEY_NAME + "=")
161                    .append(builder.getClass().getSimpleName())
162                    .append("(").append(ObjectHelper.getIdentityHashCode(builder)).append(")");
163            }
164    
165            return createObjectName(buffer);
166        }
167    
168        public ObjectName getObjectNameForConsumer(CamelContext context, Consumer consumer) throws MalformedObjectNameException {
169            StringBuilder buffer = new StringBuilder();
170            buffer.append(domainName).append(":");
171            buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
172            buffer.append(KEY_TYPE + "=").append(TYPE_CONSUMER).append(",");
173    
174            String name = consumer.getClass().getSimpleName();
175            if (ObjectHelper.isEmpty(name)) {
176                name = "Consumer";
177            }
178            buffer.append(KEY_NAME + "=")
179                .append(name)
180                .append("(").append(ObjectHelper.getIdentityHashCode(consumer)).append(")");
181            return createObjectName(buffer);
182        }
183    
184        public ObjectName getObjectNameForProducer(CamelContext context, Producer producer) throws MalformedObjectNameException {
185            StringBuilder buffer = new StringBuilder();
186            buffer.append(domainName).append(":");
187            buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
188            buffer.append(KEY_TYPE + "=").append(TYPE_PRODUCER).append(",");
189    
190            String name = producer.getClass().getSimpleName();
191            if (ObjectHelper.isEmpty(name)) {
192                name = "Producer";
193            }
194            buffer.append(KEY_NAME + "=")
195                .append(name)
196                .append("(").append(ObjectHelper.getIdentityHashCode(producer)).append(")");
197            return createObjectName(buffer);
198        }
199    
200        public ObjectName getObjectNameForTracer(CamelContext context, InterceptStrategy tracer) throws MalformedObjectNameException {
201            StringBuilder buffer = new StringBuilder();
202            buffer.append(domainName).append(":");
203            buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
204            buffer.append(KEY_TYPE + "=" + TYPE_TRACER + ",");
205            buffer.append(KEY_NAME + "=")
206                .append("Tracer")
207                .append("(").append(ObjectHelper.getIdentityHashCode(tracer)).append(")");
208            return createObjectName(buffer);
209        }
210    
211        public ObjectName getObjectNameForEventNotifier(CamelContext context, EventNotifier eventNotifier) throws MalformedObjectNameException {
212            StringBuilder buffer = new StringBuilder();
213            buffer.append(domainName).append(":");
214            buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
215            buffer.append(KEY_TYPE + "=" + TYPE_EVENT_NOTIFIER + ",");
216    
217            if (eventNotifier instanceof JmxNotificationEventNotifier) {
218                // JMX notifier shall have an easy to use name
219                buffer.append(KEY_NAME + "=").append("JmxEventNotifier");
220            } else {
221                // others can be per instance
222                buffer.append(KEY_NAME + "=")
223                    .append("EventNotifier")
224                    .append("(").append(ObjectHelper.getIdentityHashCode(eventNotifier)).append(")");
225            }
226            return createObjectName(buffer);
227        }
228    
229        public ObjectName getObjectNameForRoute(Route route) throws MalformedObjectNameException {
230            Endpoint ep = route.getEndpoint();
231            String id = route.getId();
232    
233            StringBuilder buffer = new StringBuilder();
234            buffer.append(domainName).append(":");
235            buffer.append(KEY_CONTEXT + "=").append(getContextId(ep.getCamelContext())).append(",");
236            buffer.append(KEY_TYPE + "=" + TYPE_ROUTE + ",");
237            buffer.append(KEY_NAME + "=").append(ObjectName.quote(id));
238            return createObjectName(buffer);
239        }
240    
241        public ObjectName getObjectNameForService(CamelContext context, Service service) throws MalformedObjectNameException {
242            StringBuilder buffer = new StringBuilder();
243            buffer.append(domainName).append(":");
244            buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
245            buffer.append(KEY_TYPE + "=" + TYPE_SERVICE + ",");
246            buffer.append(KEY_NAME + "=")
247                .append(service.getClass().getSimpleName())
248                .append("(").append(ObjectHelper.getIdentityHashCode(service)).append(")");
249            return createObjectName(buffer);
250        }
251    
252        public ObjectName getObjectNameForThreadPool(CamelContext context, ThreadPoolExecutor threadPool, String id, String sourceId) throws MalformedObjectNameException {
253            StringBuilder buffer = new StringBuilder();
254            buffer.append(domainName).append(":");
255            buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(",");
256            buffer.append(KEY_TYPE + "=" + TYPE_THREAD_POOL + ",");
257    
258            String name = id;
259            if (sourceId != null) {
260                // provide source id if we know it, this helps end user to know where the pool is used
261                name = name + "(" + sourceId + ")";
262            }
263            buffer.append(KEY_NAME + "=").append(ObjectName.quote(name));
264            return createObjectName(buffer);
265        }
266    
267        public String getDomainName() {
268            return domainName;
269        }
270    
271        public void setDomainName(String domainName) {
272            this.domainName = domainName;
273        }
274    
275        public String getHostName() {
276            return hostName;
277        }
278    
279        public void setHostName(String hostName) {
280            this.hostName = hostName;
281        }
282    
283        protected String getContextId(CamelContext context) {
284            if (context == null) {
285                return getContextId(VALUE_UNKNOWN);
286            } else {
287                String name = context.getManagementName() != null ? context.getManagementName() : context.getName();
288                return getContextId(name);
289            }
290        }
291    
292        protected String getContextId(String name) {
293            return hostName + "/" + (name != null ? name : VALUE_UNKNOWN);
294        }
295    
296        protected String getEndpointId(Endpoint ep) {
297            if (ep.isSingleton()) {
298                return ep.getEndpointKey();
299            } else {
300                // non singleton then add hashcoded id
301                String uri = ep.getEndpointKey();
302                int pos = uri.indexOf('?');
303                String id = (pos == -1) ? uri : uri.substring(0, pos);
304                id += "?id=" + ObjectHelper.getIdentityHashCode(ep);
305                return id;
306            }
307        }
308    
309        /**
310         * Factory method to create an ObjectName escaping any required characters
311         */
312        protected ObjectName createObjectName(StringBuilder buffer) throws MalformedObjectNameException {
313            String text = buffer.toString();
314            try {
315                return new ObjectName(text);
316            } catch (MalformedObjectNameException e) {
317                throw new MalformedObjectNameException("Could not create ObjectName from: " + text + ". Reason: " + e);
318            }
319        }
320    }