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.mbean;
018    
019    import java.io.InputStream;
020    import java.util.Collection;
021    import java.util.LinkedHashSet;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.Set;
025    import java.util.concurrent.TimeUnit;
026    
027    import javax.management.MBeanServer;
028    import javax.management.MBeanServerInvocationHandler;
029    import javax.management.ObjectName;
030    
031    import org.apache.camel.CamelContext;
032    import org.apache.camel.Endpoint;
033    import org.apache.camel.ManagementStatisticsLevel;
034    import org.apache.camel.ProducerTemplate;
035    import org.apache.camel.TimerListener;
036    import org.apache.camel.api.management.ManagedResource;
037    import org.apache.camel.api.management.mbean.ManagedCamelContextMBean;
038    import org.apache.camel.api.management.mbean.ManagedProcessorMBean;
039    import org.apache.camel.api.management.mbean.ManagedRouteMBean;
040    import org.apache.camel.model.ModelCamelContext;
041    import org.apache.camel.model.ModelHelper;
042    import org.apache.camel.model.RouteDefinition;
043    import org.apache.camel.model.RoutesDefinition;
044    
045    /**
046     * @version 
047     */
048    @ManagedResource(description = "Managed CamelContext")
049    public class ManagedCamelContext extends ManagedPerformanceCounter implements TimerListener, ManagedCamelContextMBean {
050        private final ModelCamelContext context;   
051        private final LoadTriplet load = new LoadTriplet();
052    
053        public ManagedCamelContext(ModelCamelContext context) {
054            this.context = context;
055            boolean enabled = context.getManagementStrategy().getStatisticsLevel() != ManagementStatisticsLevel.Off;
056            setStatisticsEnabled(enabled);
057        }
058    
059        public CamelContext getContext() {
060            return context;
061        }
062    
063        public String getCamelId() {
064            return context.getName();
065        }
066    
067        public String getManagementName() {
068            return context.getManagementName();
069        }
070    
071        public String getCamelVersion() {
072            return context.getVersion();
073        }
074    
075        public String getState() {
076            return context.getStatus().name();
077        }
078    
079        public String getUptime() {
080            return context.getUptime();
081        }
082    
083        public Map<String, String> getProperties() {
084            if (context.getProperties().isEmpty()) {
085                return null;
086            }
087            return context.getProperties();
088        }
089    
090        public Boolean getTracing() {
091            return context.isTracing();
092        }
093    
094        public void setTracing(Boolean tracing) {
095            context.setTracing(tracing);
096        }
097    
098        public Integer getInflightExchanges() {
099            return context.getInflightRepository().size();
100        }
101    
102        public void setTimeout(long timeout) {
103            context.getShutdownStrategy().setTimeout(timeout);
104        }
105    
106        public long getTimeout() {
107            return context.getShutdownStrategy().getTimeout();
108        }
109    
110        public void setTimeUnit(TimeUnit timeUnit) {
111            context.getShutdownStrategy().setTimeUnit(timeUnit);
112        }
113    
114        public TimeUnit getTimeUnit() {
115            return context.getShutdownStrategy().getTimeUnit();
116        }
117    
118        public void setShutdownNowOnTimeout(boolean shutdownNowOnTimeout) {
119            context.getShutdownStrategy().setShutdownNowOnTimeout(shutdownNowOnTimeout);
120        }
121    
122        public boolean isShutdownNowOnTimeout() {
123            return context.getShutdownStrategy().isShutdownNowOnTimeout();
124        }
125        
126        public String getLoad01() {
127            return String.format("%.2f", load.getLoad1());
128        }
129    
130        public String getLoad05() {
131            return String.format("%.2f", load.getLoad5());
132        }
133    
134        public String getLoad15() {
135            return String.format("%.2f", load.getLoad15());
136        }
137    
138        @Override
139        public void onTimer() {
140            load.update(getInflightExchanges());
141        }
142    
143        public void start() throws Exception {
144            if (context.isSuspended()) {
145                context.resume();
146            } else {
147                context.start();
148            }
149        }
150    
151        public void stop() throws Exception {
152            context.stop();
153        }
154    
155        public void suspend() throws Exception {
156            context.suspend();
157        }
158    
159        public void resume() throws Exception {
160            if (context.isSuspended()) {
161                context.resume();
162            } else {
163                throw new IllegalStateException("CamelContext is not suspended");
164            }
165        }
166    
167        public void sendBody(String endpointUri, Object body) throws Exception {
168            ProducerTemplate template = context.createProducerTemplate();
169            try {
170                template.sendBody(endpointUri, body);
171            } finally {
172                template.stop();
173            }
174        }
175    
176        public void sendStringBody(String endpointUri, String body) throws Exception {
177            sendBody(endpointUri, body);
178        }
179    
180        public void sendBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception {
181            ProducerTemplate template = context.createProducerTemplate();
182            try {
183                template.sendBodyAndHeaders(endpointUri, body, headers);
184            } finally {
185                template.stop();
186            }
187        }
188    
189        public Object requestBody(String endpointUri, Object body) throws Exception {
190            ProducerTemplate template = context.createProducerTemplate();
191            Object answer = null;
192            try {
193                answer = template.requestBody(endpointUri, body);
194            } finally {
195                template.stop();
196            }
197            return answer;
198        }
199    
200        public Object requestStringBody(String endpointUri, String body) throws Exception {
201            return requestBody(endpointUri, body);
202        }
203    
204        public Object requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception {
205            ProducerTemplate template = context.createProducerTemplate();
206            Object answer = null;
207            try {
208                answer = template.requestBodyAndHeaders(endpointUri, body, headers);
209            } finally {
210                template.stop();
211            }
212            return answer;
213        }
214    
215        public String dumpRoutesAsXml() throws Exception {
216            List<RouteDefinition> routes = context.getRouteDefinitions();
217            if (routes.isEmpty()) {
218                return null;
219            }
220    
221            // use a routes definition to dump the routes
222            RoutesDefinition def = new RoutesDefinition();
223            def.setRoutes(routes);
224            return ModelHelper.dumpModelAsXml(def);
225        }
226    
227        public void addOrUpdateRoutesFromXml(String xml) throws Exception {
228            // convert to model from xml
229            InputStream is = context.getTypeConverter().mandatoryConvertTo(InputStream.class, xml);
230            RoutesDefinition def = context.loadRoutesDefinition(is);
231            if (def == null) {
232                return;
233            }
234    
235            // add will remove existing route first
236            context.addRouteDefinitions(def.getRoutes());
237        }
238    
239        @Override
240        public String dumpRoutesStatsAsXml(boolean fullStats, boolean includeProcessors) throws Exception {
241            StringBuilder sb = new StringBuilder();
242            sb.append("<camelContextStat").append(String.format(" id=\"%s\"", getCamelId()));
243            // use substring as we only want the attributes
244            String stat = dumpStatsAsXml(fullStats);
245            sb.append(" ").append(stat.substring(7, stat.length() - 2)).append(">\n");
246    
247            MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer();
248            if (server != null) {
249                // gather all the routes for this CamelContext, which requires JMX
250                ObjectName query = ObjectName.getInstance("org.apache.camel:context=*/" + getContext().getManagementName() + ",type=routes,*");
251                Set<ObjectName> routes = server.queryNames(query, null);
252    
253                Set<ManagedProcessorMBean> processors = new LinkedHashSet<ManagedProcessorMBean>();
254                if (includeProcessors) {
255                    // gather all the processors for this CamelContext, which requires JMX
256                    query = ObjectName.getInstance("org.apache.camel:context=*/" + getContext().getManagementName() + ",type=processors,*");
257                    Set<ObjectName> names = server.queryNames(query, null);
258                    for (ObjectName on : names) {
259                        ManagedProcessorMBean processor = MBeanServerInvocationHandler.newProxyInstance(server, on, ManagedProcessorMBean.class, true);
260                        processors.add(processor);
261                    }
262                }
263                
264                // loop the routes, and append the processor stats if needed
265                sb.append("  <routeStats>\n");
266                for (ObjectName on : routes) {
267                    ManagedRouteMBean route = MBeanServerInvocationHandler.newProxyInstance(server, on, ManagedRouteMBean.class, true);
268                    sb.append("    <routeStat").append(String.format(" id=\"%s\"", route.getRouteId()));
269                    // use substring as we only want the attributes
270                    stat = route.dumpStatsAsXml(fullStats);
271                    sb.append(" ").append(stat.substring(7, stat.length() - 2)).append(">\n");
272    
273                    // add processor details if needed
274                    if (includeProcessors) {
275                        sb.append("      <processorStats>\n");
276                        for (ManagedProcessorMBean processor : processors) {
277                            // the processor must belong to this route
278                            if (route.getRouteId().equals(processor.getRouteId())) {
279                                sb.append("        <processorStat").append(String.format(" id=\"%s\"", processor.getProcessorId()));
280                                // use substring as we only want the attributes
281                                sb.append(" ").append(processor.dumpStatsAsXml(fullStats).substring(7)).append("\n");
282                            }
283                        }
284                        sb.append("      </processorStats>\n");
285                    }
286                    sb.append("    </routeStat>\n");
287                }
288                sb.append("  </routeStats>\n");
289            }
290    
291            sb.append("</camelContextStat>");
292            return sb.toString();
293        }
294    
295        public boolean createEndpoint(String uri) throws Exception {
296            if (context.hasEndpoint(uri) != null) {
297                // endpoint already exists
298                return false;
299            }
300    
301            Endpoint endpoint = context.getEndpoint(uri);
302            if (endpoint != null) {
303                // ensure endpoint is registered, as the management strategy could have been configured to not always
304                // register new endpoints in JMX, so we need to check if its registered, and if not register it manually
305                ObjectName on = context.getManagementStrategy().getManagementNamingStrategy().getObjectNameForEndpoint(endpoint);
306                if (on != null && !context.getManagementStrategy().getManagementAgent().isRegistered(on)) {
307                    // register endpoint as mbean
308                    Object me = context.getManagementStrategy().getManagementObjectStrategy().getManagedObjectForEndpoint(context, endpoint);
309                    context.getManagementStrategy().getManagementAgent().register(me, on);
310                }
311                return true;
312            } else {
313                return false;
314            }
315        }
316    
317        public int removeEndpoints(String pattern) throws Exception {
318            // endpoints is always removed from JMX if removed from context
319            Collection<Endpoint> removed = context.removeEndpoints(pattern);
320            return removed.size();
321        }
322    
323    }