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