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 }