blob: a42b0edbd275ccf072a7212cd1d95de123de4ebe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.commands;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.TabularData;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.Route;
import org.apache.camel.ServiceStatus;
import org.apache.camel.StatefulService;
import org.apache.camel.api.management.ManagedCamelContext;
import org.apache.camel.api.management.mbean.ManagedRouteMBean;
import org.apache.camel.model.Model;
import org.apache.camel.model.ModelHelper;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.RestsDefinition;
import org.apache.camel.spi.EndpointRegistry;
import org.apache.camel.spi.ManagementAgent;
import org.apache.camel.spi.RestRegistry;
import org.apache.camel.spi.RuntimeEndpointRegistry;
import org.apache.camel.spi.Transformer;
import org.apache.camel.spi.Validator;
/**
* Abstract {@link org.apache.camel.commands.LocalCamelController} that implementators should extend when implementing
* a controller that runs locally in the same JVM as Camel.
*/
public abstract class AbstractLocalCamelController extends AbstractCamelController implements LocalCamelController {
@Override
public CamelContext getLocalCamelContext(String name) throws Exception {
for (CamelContext camelContext : this.getLocalCamelContexts()) {
if (camelContext.getName().equals(name)) {
return camelContext;
}
}
return null;
}
@Override
public Map<String, Object> getCamelContextInformation(String name) throws Exception {
Map<String, Object> answer = new LinkedHashMap<>();
CamelContext context = getLocalCamelContext(name);
if (context != null) {
answer.put("name", context.getName());
answer.put("managementName", context.getManagementName());
answer.put("version", context.getVersion());
answer.put("status", context.getStatus().name());
answer.put("uptime", context.getUptime());
answer.put("suspended", context.getStatus().isSuspended());
if (context.getManagementStrategy().getManagementAgent() != null) {
String level = context.getManagementStrategy().getManagementAgent().getStatisticsLevel().name();
answer.put("managementStatisticsLevel", level);
}
answer.put("allowUseOriginalMessage", context.isAllowUseOriginalMessage());
answer.put("messageHistory", context.isMessageHistory());
answer.put("tracing", context.isTracing());
answer.put("logMask", context.isLogMask());
answer.put("shutdownTimeout", context.getShutdownStrategy().getTimeUnit().toSeconds(context.getShutdownStrategy().getTimeout()));
answer.put("classResolver", context.getClassResolver().toString());
answer.put("packageScanClassResolver", context.adapt(ExtendedCamelContext.class).getPackageScanClassResolver().toString());
answer.put("applicationContextClassLoader", context.getApplicationContextClassLoader().toString());
answer.put("headersMapFactory", context.getHeadersMapFactory().toString());
for (Map.Entry<String, String> entry : context.getGlobalOptions().entrySet()) {
answer.put("property." + entry.getKey(), entry.getValue());
}
long activeRoutes = 0;
long inactiveRoutes = 0;
List<Route> routeList = context.getRoutes();
for (Route route : routeList) {
if (context.getRouteController().getRouteStatus(route.getId()).isStarted()) {
activeRoutes++;
} else {
inactiveRoutes++;
}
}
answer.put("startedRoutes", activeRoutes);
answer.put("totalRoutes", activeRoutes + inactiveRoutes);
// add type converter details
answer.put("typeConverter.numberOfTypeConverters", context.getTypeConverterRegistry().size());
answer.put("typeConverter.statisticsEnabled", context.getTypeConverterRegistry().getStatistics().isStatisticsEnabled());
answer.put("typeConverter.noopCounter", context.getTypeConverterRegistry().getStatistics().getNoopCounter());
answer.put("typeConverter.attemptCounter", context.getTypeConverterRegistry().getStatistics().getAttemptCounter());
answer.put("typeConverter.hitCounter", context.getTypeConverterRegistry().getStatistics().getHitCounter());
answer.put("typeConverter.missCounter", context.getTypeConverterRegistry().getStatistics().getMissCounter());
answer.put("typeConverter.failedCounter", context.getTypeConverterRegistry().getStatistics().getFailedCounter());
// add async processor await manager details
ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);
answer.put("asyncProcessorAwaitManager.size", ecc.getAsyncProcessorAwaitManager().size());
answer.put("asyncProcessorAwaitManager.statisticsEnabled", ecc.getAsyncProcessorAwaitManager().getStatistics().isStatisticsEnabled());
answer.put("asyncProcessorAwaitManager.threadsBlocked", ecc.getAsyncProcessorAwaitManager().getStatistics().getThreadsBlocked());
answer.put("asyncProcessorAwaitManager.threadsInterrupted", ecc.getAsyncProcessorAwaitManager().getStatistics().getThreadsInterrupted());
answer.put("asyncProcessorAwaitManager.totalDuration", ecc.getAsyncProcessorAwaitManager().getStatistics().getTotalDuration());
answer.put("asyncProcessorAwaitManager.minDuration", ecc.getAsyncProcessorAwaitManager().getStatistics().getMinDuration());
answer.put("asyncProcessorAwaitManager.maxDuration", ecc.getAsyncProcessorAwaitManager().getStatistics().getMaxDuration());
answer.put("asyncProcessorAwaitManager.meanDuration", ecc.getAsyncProcessorAwaitManager().getStatistics().getMeanDuration());
// add stream caching details if enabled
if (context.getStreamCachingStrategy().isEnabled()) {
answer.put("streamCachingEnabled", true);
answer.put("streamCaching.spoolDirectory", context.getStreamCachingStrategy().getSpoolDirectory());
answer.put("streamCaching.spoolCipher", context.getStreamCachingStrategy().getSpoolCipher());
answer.put("streamCaching.spoolThreshold", context.getStreamCachingStrategy().getSpoolThreshold());
answer.put("streamCaching.spoolUsedHeapMemoryThreshold", context.getStreamCachingStrategy().getSpoolUsedHeapMemoryThreshold());
answer.put("streamCaching.spoolUsedHeapMemoryLimit", context.getStreamCachingStrategy().getSpoolUsedHeapMemoryLimit());
answer.put("streamCaching.anySpoolRules", context.getStreamCachingStrategy().isAnySpoolRules());
answer.put("streamCaching.bufferSize", context.getStreamCachingStrategy().getBufferSize());
answer.put("streamCaching.removeSpoolDirectoryWhenStopping", context.getStreamCachingStrategy().isRemoveSpoolDirectoryWhenStopping());
answer.put("streamCaching.statisticsEnabled", context.getStreamCachingStrategy().getStatistics().isStatisticsEnabled());
if (context.getStreamCachingStrategy().getStatistics().isStatisticsEnabled()) {
answer.put("streamCaching.cacheMemoryCounter", context.getStreamCachingStrategy().getStatistics().getCacheMemoryCounter());
answer.put("streamCaching.cacheMemorySize", context.getStreamCachingStrategy().getStatistics().getCacheMemorySize());
answer.put("streamCaching.cacheMemoryAverageSize", context.getStreamCachingStrategy().getStatistics().getCacheMemoryAverageSize());
answer.put("streamCaching.cacheSpoolCounter", context.getStreamCachingStrategy().getStatistics().getCacheSpoolCounter());
answer.put("streamCaching.cacheSpoolSize", context.getStreamCachingStrategy().getStatistics().getCacheSpoolSize());
answer.put("streamCaching.cacheSpoolAverageSize", context.getStreamCachingStrategy().getStatistics().getCacheSpoolAverageSize());
}
} else {
answer.put("streamCachingEnabled", false);
}
}
return answer;
}
@Override
public String getCamelContextStatsAsXml(String camelContextName, boolean fullStats, boolean includeProcessors) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return null;
}
ManagementAgent agent = context.getManagementStrategy().getManagementAgent();
if (agent != null) {
MBeanServer mBeanServer = agent.getMBeanServer();
ObjectName query = ObjectName.getInstance(agent.getMBeanObjectDomainName() + ":type=context,*");
Set<ObjectName> set = mBeanServer.queryNames(query, null);
for (ObjectName contextMBean : set) {
String camelId = (String) mBeanServer.getAttribute(contextMBean, "CamelId");
if (camelId != null && camelId.equals(context.getName())) {
String xml = (String) mBeanServer.invoke(contextMBean, "dumpRoutesStatsAsXml", new Object[]{fullStats, includeProcessors}, new String[]{"boolean", "boolean"});
return xml;
}
}
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public List<Map<String, Object>> browseInflightExchanges(String camelContextName, String route, int limit, boolean sortByLongestDuration) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return null;
}
List<Map<String, Object>> answer = new ArrayList<>();
ManagementAgent agent = context.getManagementStrategy().getManagementAgent();
if (agent != null) {
MBeanServer mBeanServer = agent.getMBeanServer();
ObjectName on = new ObjectName(agent.getMBeanObjectDomainName() + ":type=services,name=DefaultInflightRepository,context=" + context.getManagementName());
if (mBeanServer.isRegistered(on)) {
TabularData list = (TabularData) mBeanServer.invoke(on, "browse", new Object[]{route, limit, sortByLongestDuration}, new String[]{"java.lang.String", "int", "boolean"});
Collection<CompositeData> values = (Collection<CompositeData>) list.values();
for (CompositeData data : values) {
Map<String, Object> row = new LinkedHashMap<>();
Object exchangeId = data.get("exchangeId");
if (exchangeId != null) {
row.put("exchangeId", exchangeId);
}
Object fromRouteId = data.get("fromRouteId");
if (fromRouteId != null) {
row.put("fromRouteId", fromRouteId);
}
Object routeId = data.get("routeId");
if (routeId != null) {
row.put("routeId", routeId);
}
Object nodeId = data.get("nodeId");
if (nodeId != null) {
row.put("nodeId", nodeId);
}
Object elapsed = data.get("elapsed");
if (elapsed != null) {
row.put("elapsed", elapsed);
}
Object duration = data.get("duration");
if (duration != null) {
row.put("duration", duration);
}
answer.add(row);
}
}
}
return answer;
}
@Override
public void startContext(String camelContextName) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
if (context.getStatus().equals(ServiceStatus.Suspended)) {
context.resume();
} else {
context.start();
}
}
}
@Override
public void stopContext(String camelContextName) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
context.stop();
}
}
@Override
public void suspendContext(String camelContextName) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
context.suspend();
}
}
@Override
public void resumeContext(String camelContextName) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
context.resume();
}
}
@Override
public List<Map<String, String>> getRoutes(String camelContextName) throws Exception {
return getRoutes(camelContextName, null);
}
@Override
public List<Map<String, String>> getRoutes(String camelContextName, String filter) throws Exception {
List<Map<String, String>> answer = new ArrayList<>();
if (camelContextName != null) {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context != null) {
for (Route route : context.getRoutes()) {
if (filter == null || route.getId().matches(filter)) {
Map<String, String> row = new LinkedHashMap<>();
row.put("camelContextName", context.getName());
row.put("routeId", route.getId());
row.put("state", getRouteState(route));
row.put("uptime", route.getUptime());
ManagedCamelContext mcc = context.getExtension(ManagedCamelContext.class);
if (mcc != null && mcc.getManagedCamelContext() != null) {
ManagedRouteMBean mr = mcc.getManagedRoute(route.getId());
row.put("exchangesTotal", "" + mr.getExchangesTotal());
row.put("exchangesInflight", "" + mr.getExchangesInflight());
row.put("exchangesFailed", "" + mr.getExchangesFailed());
} else {
row.put("exchangesTotal", "0");
row.put("exchangesInflight", "0");
row.put("exchangesFailed", "0");
}
answer.add(row);
}
}
}
} else {
List<Map<String, String>> camelContexts = this.getCamelContexts();
for (Map<String, String> row : camelContexts) {
List<Map<String, String>> routes = getRoutes(row.get("name"), filter);
answer.addAll(routes);
}
}
// sort the list
Collections.sort(answer, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> o1, Map<String, String> o2) {
// group by camel context first, then by route name
String c1 = o1.get("camelContextName");
String c2 = o2.get("camelContextName");
int answer = c1.compareTo(c2);
if (answer == 0) {
// okay from same camel context, then sort by route id
answer = o1.get("routeId").compareTo(o2.get("routeId"));
}
return answer;
}
});
return answer;
}
@Override
public void resetRouteStats(String camelContextName) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return;
}
ManagementAgent agent = context.getManagementStrategy().getManagementAgent();
if (agent != null) {
MBeanServer mBeanServer = agent.getMBeanServer();
// reset route mbeans
ObjectName query = ObjectName.getInstance(agent.getMBeanObjectDomainName() + ":type=routes,*");
Set<ObjectName> set = mBeanServer.queryNames(query, null);
for (ObjectName routeMBean : set) {
String camelId = (String) mBeanServer.getAttribute(routeMBean, "CamelId");
if (camelId != null && camelId.equals(context.getName())) {
mBeanServer.invoke(routeMBean, "reset", new Object[]{true}, new String[]{"boolean"});
}
}
}
}
@Override
public void startRoute(String camelContextName, String routeId) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
context.getRouteController().startRoute(routeId);
}
}
@Override
public void stopRoute(String camelContextName, String routeId) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
context.getRouteController().stopRoute(routeId);
}
}
@Override
public void suspendRoute(String camelContextName, String routeId) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
context.getRouteController().suspendRoute(routeId);
}
}
@Override
public void resumeRoute(String camelContextName, String routeId) throws Exception {
CamelContext context = getLocalCamelContext(camelContextName);
if (context != null) {
context.getRouteController().resumeRoute(routeId);
}
}
@Override
public String getRouteModelAsXml(String routeId, String camelContextName) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return null;
}
RouteDefinition route = context.getExtension(Model.class).getRouteDefinition(routeId);
if (route == null) {
return null;
}
return ModelHelper.dumpModelAsXml(context, route);
}
@Override
public String getRouteStatsAsXml(String routeId, String camelContextName, boolean fullStats, boolean includeProcessors) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return null;
}
ManagementAgent agent = context.getManagementStrategy().getManagementAgent();
if (agent != null) {
MBeanServer mBeanServer = agent.getMBeanServer();
Set<ObjectName> set = mBeanServer.queryNames(new ObjectName(agent.getMBeanObjectDomainName() + ":type=routes,name=\"" + routeId + "\",*"), null);
for (ObjectName routeMBean : set) {
// the route must be part of the camel context
String camelId = (String) mBeanServer.getAttribute(routeMBean, "CamelId");
if (camelId != null && camelId.equals(camelContextName)) {
String xml = (String) mBeanServer.invoke(routeMBean, "dumpRouteStatsAsXml", new Object[]{fullStats, includeProcessors}, new String[]{"boolean", "boolean"});
return xml;
}
}
}
return null;
}
@Override
public String getStepStatsAsXml(String routeId, String camelContextName, boolean fullStats) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return null;
}
ManagementAgent agent = context.getManagementStrategy().getManagementAgent();
if (agent != null) {
MBeanServer mBeanServer = agent.getMBeanServer();
Set<ObjectName> set = mBeanServer.queryNames(new ObjectName(agent.getMBeanObjectDomainName() + ":type=routes,name=\"" + routeId + "\",*"), null);
for (ObjectName routeMBean : set) {
// the route must be part of the camel context
String camelId = (String) mBeanServer.getAttribute(routeMBean, "CamelId");
if (camelId != null && camelId.equals(camelContextName)) {
String xml = (String) mBeanServer.invoke(routeMBean, "dumpStepStatsAsXml", new Object[]{fullStats}, new String[]{"boolean"});
return xml;
}
}
}
return null;
}
@Override
public String getRestModelAsXml(String camelContextName) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return null;
}
List<RestDefinition> rests = context.getExtension(Model.class).getRestDefinitions();
if (rests == null || rests.isEmpty()) {
return null;
}
// use a rests definition to dump the rests
RestsDefinition def = new RestsDefinition();
def.setRests(rests);
return ModelHelper.dumpModelAsXml(context, def);
}
@Override
public String getRestApiDocAsJson(String camelContextName) throws Exception {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context == null) {
return null;
}
return context.getRestRegistry().apiDocAsJson();
}
@Override
public List<Map<String, String>> getEndpoints(String camelContextName) throws Exception {
List<Map<String, String>> answer = new ArrayList<>();
if (camelContextName != null) {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context != null) {
List<Endpoint> endpoints = new ArrayList<>(context.getEndpoints());
// sort routes
Collections.sort(endpoints, new Comparator<Endpoint>() {
@Override
public int compare(Endpoint o1, Endpoint o2) {
return o1.getEndpointKey().compareTo(o2.getEndpointKey());
}
});
for (Endpoint endpoint : endpoints) {
Map<String, String> row = new LinkedHashMap<>();
row.put("camelContextName", context.getName());
row.put("uri", endpoint.getEndpointUri());
row.put("state", getEndpointState(endpoint));
answer.add(row);
}
}
}
return answer;
}
@Override
public List<Map<String, String>> getEndpointRuntimeStatistics(String camelContextName) throws Exception {
List<Map<String, String>> answer = new ArrayList<>();
if (camelContextName != null) {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context != null && context.getRuntimeEndpointRegistry() != null) {
EndpointRegistry staticRegistry = context.getEndpointRegistry();
for (RuntimeEndpointRegistry.Statistic stat : context.getRuntimeEndpointRegistry().getEndpointStatistics()) {
String url = stat.getUri();
String routeId = stat.getRouteId();
String direction = stat.getDirection();
Boolean isStatic = staticRegistry.isStatic(url);
Boolean isDynamic = staticRegistry.isDynamic(url);
long hits = stat.getHits();
Map<String, String> row = new LinkedHashMap<>();
row.put("camelContextName", context.getName());
row.put("uri", url);
row.put("routeId", routeId);
row.put("direction", direction);
row.put("static", isStatic.toString());
row.put("dynamic", isDynamic.toString());
row.put("hits", "" + hits);
answer.add(row);
}
}
// sort the list
Collections.sort(answer, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> endpoint1, Map<String, String> endpoint2) {
// sort by route id
String route1 = endpoint1.get("routeId");
String route2 = endpoint2.get("routeId");
int num = route1.compareTo(route2);
if (num == 0) {
// we want in before out
String dir1 = endpoint1.get("direction");
String dir2 = endpoint2.get("direction");
num = dir1.compareTo(dir2);
}
return num;
}
});
}
return answer;
}
@Override
public List<Map<String, String>> getRestServices(String camelContextName) throws Exception {
List<Map<String, String>> answer = new ArrayList<>();
if (camelContextName != null) {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context != null) {
List<RestRegistry.RestService> services = new ArrayList<>(context.getRestRegistry().listAllRestServices());
Collections.sort(services, new Comparator<RestRegistry.RestService>() {
@Override
public int compare(RestRegistry.RestService o1, RestRegistry.RestService o2) {
return o1.getUrl().compareTo(o2.getUrl());
}
});
for (RestRegistry.RestService service : services) {
Map<String, String> row = new LinkedHashMap<>();
row.put("basePath", service.getBasePath());
row.put("baseUrl", service.getBaseUrl());
row.put("consumes", service.getConsumes());
row.put("description", service.getDescription());
row.put("inType", service.getInType());
row.put("method", service.getMethod());
row.put("outType", service.getOutType());
row.put("produces", service.getProduces());
row.put("routeId", service.getRouteId());
row.put("state", service.getState());
row.put("uriTemplate", service.getUriTemplate());
row.put("url", service.getUrl());
answer.add(row);
}
}
}
return answer;
}
@Override
public List<Map<String, String>> getTransformers(String camelContextName) throws Exception {
List<Map<String, String>> answer = new ArrayList<>();
if (camelContextName != null) {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context != null) {
List<Transformer> transformers = new ArrayList<>(context.getTransformerRegistry().values());
for (Transformer transformer : transformers) {
Map<String, String> row = new LinkedHashMap<>();
row.put("camelContextName", context.getName());
row.put("scheme", transformer.getModel());
row.put("from", transformer.getFrom().toString());
row.put("to", transformer.getTo().toString());
row.put("state", transformer.getStatus().toString());
row.put("description", transformer.toString());
answer.add(row);
}
}
}
return answer;
}
@Override
public List<Map<String, String>> getValidators(String camelContextName) throws Exception {
List<Map<String, String>> answer = new ArrayList<>();
if (camelContextName != null) {
CamelContext context = this.getLocalCamelContext(camelContextName);
if (context != null) {
List<Validator> validators = new ArrayList<>(context.getValidatorRegistry().values());
for (Validator validator : validators) {
Map<String, String> row = new LinkedHashMap<>();
row.put("camelContextName", context.getName());
row.put("type", validator.getType().toString());
row.put("state", validator.getStatus().toString());
row.put("description", validator.toString());
answer.add(row);
}
}
}
return answer;
}
private static String getEndpointState(Endpoint endpoint) {
// must use String type to be sure remote JMX can read the attribute without requiring Camel classes.
if (endpoint instanceof StatefulService) {
ServiceStatus status = ((StatefulService) endpoint).getStatus();
return status.name();
}
// assume started if not a ServiceSupport instance
return ServiceStatus.Started.name();
}
private static String getRouteState(Route route) {
// must use String type to be sure remote JMX can read the attribute without requiring Camel classes.
ServiceStatus status = route.getCamelContext().getRouteController().getRouteStatus(route.getId());
if (status != null) {
return status.name();
}
// assume started if not a ServiceSupport instance
return ServiceStatus.Started.name();
}
}