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 }