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 */ 017package org.apache.camel.management.mbean; 018 019import java.io.PrintWriter; 020import java.io.StringWriter; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.Comparator; 024import java.util.Set; 025import java.util.TreeSet; 026import java.util.stream.Collectors; 027 028import javax.management.openmbean.CompositeData; 029import javax.management.openmbean.CompositeDataSupport; 030import javax.management.openmbean.CompositeType; 031import javax.management.openmbean.TabularData; 032import javax.management.openmbean.TabularDataSupport; 033 034import org.apache.camel.CamelContext; 035import org.apache.camel.Route; 036import org.apache.camel.RuntimeCamelException; 037import org.apache.camel.api.management.ManagedResource; 038import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes; 039import org.apache.camel.api.management.mbean.ManagedSupervisingRouteControllerMBean; 040import org.apache.camel.spi.SupervisingRouteController; 041import org.apache.camel.util.TimeUtils; 042import org.apache.camel.util.backoff.BackOffTimer; 043 044@ManagedResource(description = "Managed SupervisingRouteController") 045public class ManagedSupervisingRouteController extends ManagedService implements ManagedSupervisingRouteControllerMBean { 046 047 private final SupervisingRouteController controller; 048 049 public ManagedSupervisingRouteController(CamelContext context, SupervisingRouteController controller) { 050 super(context, controller); 051 this.controller = controller; 052 } 053 054 public SupervisingRouteController getRouteController() { 055 return controller; 056 } 057 058 @Override 059 public boolean isEnabled() { 060 return true; 061 } 062 063 @Override 064 public int getThreadPoolSize() { 065 return controller.getThreadPoolSize(); 066 } 067 068 @Override 069 public long getInitialDelay() { 070 return controller.getInitialDelay(); 071 } 072 073 @Override 074 public long getBackOffDelay() { 075 return controller.getBackOffDelay(); 076 } 077 078 @Override 079 public long getBackOffMaxDelay() { 080 return controller.getBackOffMaxDelay(); 081 } 082 083 @Override 084 public long getBackOffMaxElapsedTime() { 085 return controller.getBackOffMaxElapsedTime(); 086 } 087 088 @Override 089 public long getBackOffMaxAttempts() { 090 return controller.getBackOffMaxAttempts(); 091 } 092 093 @Override 094 public double getBackOffMultiplier() { 095 return controller.getBackOffMultiplier(); 096 } 097 098 @Override 099 public String getIncludeRoutes() { 100 return controller.getIncludeRoutes(); 101 } 102 103 @Override 104 public String getExcludeRoutes() { 105 return controller.getExcludeRoutes(); 106 } 107 108 @Override 109 public int getNumberOfControlledRoutes() { 110 return controller.getControlledRoutes().size(); 111 } 112 113 @Override 114 public int getNumberOfRestartingRoutes() { 115 return controller.getRestartingRoutes().size(); 116 } 117 118 @Override 119 public int getNumberOfExhaustedRoutes() { 120 return controller.getExhaustedRoutes().size(); 121 } 122 123 @Override 124 public Collection<String> getControlledRoutes() { 125 if (controller != null) { 126 return controller.getControlledRoutes().stream() 127 .map(Route::getId) 128 .collect(Collectors.toList()); 129 } 130 131 return Collections.emptyList(); 132 } 133 134 @Override 135 public String getRouteStartupLoggingLevel() { 136 if (controller != null) { 137 return controller.getRouteStartupLoggingLevel().name(); 138 } else { 139 return null; 140 } 141 } 142 143 @Override 144 public Collection<String> getRestartingRoutes() { 145 if (controller != null) { 146 return controller.getRestartingRoutes().stream() 147 .map(Route::getId) 148 .collect(Collectors.toList()); 149 } 150 151 return Collections.emptyList(); 152 } 153 154 @Override 155 public Collection<String> getExhaustedRoutes() { 156 if (controller != null) { 157 return controller.getExhaustedRoutes().stream() 158 .map(Route::getId) 159 .collect(Collectors.toList()); 160 } 161 162 return Collections.emptyList(); 163 } 164 165 @Override 166 public TabularData routeStatus(boolean exhausted, boolean restarting, boolean includeStacktrace) { 167 try { 168 TabularData answer = new TabularDataSupport(CamelOpenMBeanTypes.supervisingRouteControllerRouteStatusTabularType()); 169 170 int index = 0; 171 Set<Route> routes = new TreeSet<>(Comparator.comparing(Route::getId)); 172 routes.addAll(controller.getControlledRoutes()); 173 if (exhausted) { 174 routes.addAll(controller.getExhaustedRoutes()); 175 } 176 if (restarting) { 177 routes.addAll(controller.getRestartingRoutes()); 178 } 179 180 for (Route route : routes) { 181 CompositeType ct = CamelOpenMBeanTypes.supervisingRouteControllerRouteStatusCompositeType(); 182 183 String routeId = route.getRouteId(); 184 String status = controller.getRouteStatus(routeId).name(); 185 BackOffTimer.Task state = controller.getRestartingRouteState(routeId); 186 String supervising = state != null ? state.getStatus().name() : ""; 187 long attempts = state != null ? state.getCurrentAttempts() : 0; 188 String elapsed = ""; 189 String last = ""; 190 // we can only track elapsed/time for active supervised routes 191 long time = state != null && BackOffTimer.Task.Status.Active == state.getStatus() 192 ? state.getFirstAttemptTime() : 0; 193 if (time > 0) { 194 long delta = System.currentTimeMillis() - time; 195 elapsed = TimeUtils.printDuration(delta); 196 } 197 time = state != null && BackOffTimer.Task.Status.Active == state.getStatus() ? state.getLastAttemptTime() : 0; 198 if (time > 0) { 199 long delta = System.currentTimeMillis() - time; 200 last = TimeUtils.printDuration(delta); 201 } 202 String error = ""; 203 String stacktrace = ""; 204 Throwable cause = controller.getRestartException(routeId); 205 if (cause != null) { 206 error = cause.getMessage(); 207 if (includeStacktrace) { 208 StringWriter writer = new StringWriter(); 209 cause.printStackTrace(new PrintWriter(writer)); 210 writer.flush(); 211 stacktrace = writer.toString(); 212 } 213 } 214 215 CompositeData data = new CompositeDataSupport( 216 ct, 217 new String[] { 218 "index", "routeId", "status", "supervising", "attempts", "elapsed", "last", "error", 219 "stacktrace" }, 220 new Object[] { index, routeId, status, supervising, attempts, elapsed, last, error, stacktrace }); 221 answer.put(data); 222 223 // use a counter as the single index in the TabularData as we do not want a multi-value index 224 index++; 225 } 226 return answer; 227 } catch (Exception e) { 228 throw RuntimeCamelException.wrapRuntimeCamelException(e); 229 } 230 } 231}