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.util.List;
020    import java.util.Set;
021    import java.util.concurrent.TimeUnit;
022    import javax.management.MBeanServer;
023    import javax.management.MBeanServerInvocationHandler;
024    import javax.management.ObjectName;
025    
026    import org.apache.camel.CamelContext;
027    import org.apache.camel.Endpoint;
028    import org.apache.camel.ManagementStatisticsLevel;
029    import org.apache.camel.Route;
030    import org.apache.camel.ServiceStatus;
031    import org.apache.camel.TimerListener;
032    import org.apache.camel.api.management.ManagedResource;
033    import org.apache.camel.api.management.mbean.ManagedProcessorMBean;
034    import org.apache.camel.api.management.mbean.ManagedRouteMBean;
035    import org.apache.camel.model.ModelCamelContext;
036    import org.apache.camel.model.ModelHelper;
037    import org.apache.camel.model.RouteDefinition;
038    import org.apache.camel.spi.RoutePolicy;
039    import org.apache.camel.util.ObjectHelper;
040    
041    @ManagedResource(description = "Managed Route")
042    public class ManagedRoute extends ManagedPerformanceCounter implements TimerListener, ManagedRouteMBean {
043        public static final String VALUE_UNKNOWN = "Unknown";
044        protected final Route route;
045        protected final String description;
046        protected final ModelCamelContext context;
047        private final LoadTriplet load = new LoadTriplet();
048    
049        public ManagedRoute(ModelCamelContext context, Route route) {
050            this.route = route;
051            this.context = context;
052            this.description = route.toString();
053            boolean enabled = context.getManagementStrategy().getStatisticsLevel() != ManagementStatisticsLevel.Off;
054            setStatisticsEnabled(enabled);
055        }
056    
057        public Route getRoute() {
058            return route;
059        }
060    
061        public CamelContext getContext() {
062            return context;
063        }
064    
065        public String getRouteId() {
066            String id = route.getId();
067            if (id == null) {
068                id = VALUE_UNKNOWN;
069            }
070            return id;
071        }
072    
073        public String getDescription() {
074            return description;
075        }
076    
077        public String getEndpointUri() {
078            Endpoint ep = route.getEndpoint();
079            return ep != null ? ep.getEndpointUri() : VALUE_UNKNOWN;
080        }
081    
082        public String getState() {
083            // must use String type to be sure remote JMX can read the attribute without requiring Camel classes.
084            ServiceStatus status = context.getRouteStatus(route.getId());
085            // if no status exists then its stopped
086            if (status == null) {
087                status = ServiceStatus.Stopped;
088            }
089            return status.name();
090        }
091    
092        public Integer getInflightExchanges() {
093            return context.getInflightRepository().size(route.getId());
094        }
095    
096        public String getCamelId() {
097            return context.getName();
098        }
099    
100        public Boolean getTracing() {
101            return route.getRouteContext().isTracing();
102        }
103    
104        public void setTracing(Boolean tracing) {
105            route.getRouteContext().setTracing(tracing);
106        }
107    
108        public String getRoutePolicyList() {
109            List<RoutePolicy> policyList = route.getRouteContext().getRoutePolicyList();
110    
111            if (policyList == null || policyList.isEmpty()) {
112                // return an empty string to have it displayed nicely in JMX consoles
113                return "";
114            }
115    
116            StringBuilder sb = new StringBuilder();
117            for (int i = 0; i < policyList.size(); i++) {
118                RoutePolicy policy = policyList.get(i);
119                sb.append(policy.getClass().getSimpleName());
120                sb.append("(").append(ObjectHelper.getIdentityHashCode(policy)).append(")");
121                if (i < policyList.size() - 1) {
122                    sb.append(", ");
123                }
124            }
125            return sb.toString();
126        }
127    
128        public String getLoad01() {
129            return String.format("%.2f", load.getLoad1());
130        }
131    
132        public String getLoad05() {
133            return String.format("%.2f", load.getLoad5());
134        }
135    
136        public String getLoad15() {
137            return String.format("%.2f", load.getLoad15());
138        }
139    
140        @Override
141        public void onTimer() {
142            load.update(getInflightExchanges());
143        }
144        
145        public void start() throws Exception {
146            if (!context.getStatus().isStarted()) {
147                throw new IllegalArgumentException("CamelContext is not started");
148            }
149            context.startRoute(getRouteId());
150        }
151    
152        public void stop() throws Exception {
153            if (!context.getStatus().isStarted()) {
154                throw new IllegalArgumentException("CamelContext is not started");
155            }
156            context.stopRoute(getRouteId());
157        }
158    
159        public void stop(long timeout) throws Exception {
160            if (!context.getStatus().isStarted()) {
161                throw new IllegalArgumentException("CamelContext is not started");
162            }
163            context.stopRoute(getRouteId(), timeout, TimeUnit.SECONDS);
164        }
165    
166        public boolean stop(Long timeout, Boolean abortAfterTimeout) throws Exception {
167            if (!context.getStatus().isStarted()) {
168                throw new IllegalArgumentException("CamelContext is not started");
169            }
170            return context.stopRoute(getRouteId(), timeout, TimeUnit.SECONDS, abortAfterTimeout);
171        }
172    
173        public void shutdown() throws Exception {
174            if (!context.getStatus().isStarted()) {
175                throw new IllegalArgumentException("CamelContext is not started");
176            }
177            String routeId = getRouteId(); 
178            context.stopRoute(routeId);
179            context.removeRoute(routeId);
180        }
181    
182        public void shutdown(long timeout) throws Exception {
183            if (!context.getStatus().isStarted()) {
184                throw new IllegalArgumentException("CamelContext is not started");
185            }
186            String routeId = getRouteId(); 
187            context.stopRoute(routeId, timeout, TimeUnit.SECONDS);
188            context.removeRoute(routeId);
189        }
190    
191        public boolean remove() throws Exception {
192            if (!context.getStatus().isStarted()) {
193                throw new IllegalArgumentException("CamelContext is not started");
194            }
195            return context.removeRoute(getRouteId());
196        }
197    
198        public String dumpRouteAsXml() throws Exception {
199            String id = route.getId();
200            RouteDefinition def = context.getRouteDefinition(id);
201            if (def != null) {
202                return ModelHelper.dumpModelAsXml(def);
203            }
204            return null;
205        }
206    
207        public void updateRouteFromXml(String xml) throws Exception {
208            // convert to model from xml
209            RouteDefinition def = ModelHelper.createModelFromXml(xml, RouteDefinition.class);
210            if (def == null) {
211                return;
212            }
213    
214            // add will remove existing route first
215            context.addRouteDefinition(def);
216        }
217    
218        public String dumpRouteStatsAsXml(boolean fullStats, boolean includeProcessors) throws Exception {
219            StringBuilder sb = new StringBuilder();
220    
221            sb.append("<routeStat").append(String.format(" id=\"%s\"", route.getId()));
222            // use substring as we only want the attributes
223            String stat = dumpStatsAsXml(fullStats);
224            sb.append(" ").append(stat.substring(7, stat.length() - 2)).append(">\n");
225    
226            // gather all the processors for this route, which requires JMX
227            if (includeProcessors) {
228                sb.append("  <processorStats>\n");
229                MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer();
230                if (server != null) {
231                    ObjectName query = ObjectName.getInstance("org.apache.camel:context=*/" + getContext().getManagementName() + ",type=processors,*");
232                    Set<ObjectName> names = server.queryNames(query, null);
233                    for (ObjectName on : names) {
234                        ManagedProcessorMBean processor = MBeanServerInvocationHandler.newProxyInstance(server, on, ManagedProcessorMBean.class, true);
235                        // the processor must belong to this route
236                        if (getRouteId().equals(processor.getRouteId())) {
237                            sb.append("    <processorStat").append(String.format(" id=\"%s\"", processor.getProcessorId()));
238                            // use substring as we only want the attributes
239                            sb.append(" ").append(processor.dumpStatsAsXml(fullStats).substring(7)).append("\n");
240                        }
241                    }
242                }
243                sb.append("  </processorStats>\n");
244            }
245    
246            sb.append("</routeStat>");
247            return sb.toString();
248        }
249    
250        @Override
251        public boolean equals(Object o) {
252            return this == o || (o != null && getClass() == o.getClass() && route.equals(((ManagedRoute)o).route));
253        }
254    
255        @Override
256        public int hashCode() {
257            return route.hashCode();
258        }
259    }