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.impl.health; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025import java.util.concurrent.ConcurrentHashMap; 026import java.util.concurrent.ConcurrentMap; 027import java.util.concurrent.CopyOnWriteArrayList; 028import java.util.stream.Stream; 029 030import org.apache.camel.CamelContext; 031import org.apache.camel.CamelContextAware; 032import org.apache.camel.Route; 033import org.apache.camel.api.management.mbean.ManagedRouteMBean; 034import org.apache.camel.health.HealthCheck; 035import org.apache.camel.health.HealthCheckRepository; 036 037public class RoutesHealthCheckRepository implements CamelContextAware, HealthCheckRepository { 038 private final ConcurrentMap<Route, HealthCheck> checks; 039 private Set<String> blacklist; 040 private List<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators; 041 private ConcurrentMap<String, Collection<PerformanceCounterEvaluator<ManagedRouteMBean>>> evaluatorMap; 042 private volatile CamelContext context; 043 044 public RoutesHealthCheckRepository() { 045 this.checks = new ConcurrentHashMap<>(); 046 } 047 048 @Override 049 public void setCamelContext(CamelContext camelContext) { 050 this.context = camelContext; 051 } 052 053 @Override 054 public CamelContext getCamelContext() { 055 return context; 056 } 057 058 public void setBlacklistedRoutes(Collection<String> blacklistedRoutes) { 059 blacklistedRoutes.forEach(this::addBlacklistedRoute); 060 } 061 062 public void addBlacklistedRoute(String routeId) { 063 if (this.blacklist == null) { 064 this.blacklist = new HashSet<>(); 065 } 066 067 this.blacklist.add(routeId); 068 } 069 070 public void setEvaluators(Collection<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators) { 071 evaluators.forEach(this::addEvaluator); 072 } 073 074 public void addEvaluator(PerformanceCounterEvaluator<ManagedRouteMBean> evaluator) { 075 if (this.evaluators == null) { 076 this.evaluators = new CopyOnWriteArrayList<>(); 077 } 078 079 this.evaluators.add(evaluator); 080 } 081 082 public void setRoutesEvaluators(Map<String, Collection<PerformanceCounterEvaluator<ManagedRouteMBean>>> evaluators) { 083 evaluators.forEach(this::setRouteEvaluators); 084 } 085 086 public void setRouteEvaluators(String routeId, Collection<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators) { 087 evaluators.forEach(evaluator -> addRouteEvaluator(routeId, evaluator)); 088 } 089 090 public void addRouteEvaluator(String routeId, PerformanceCounterEvaluator<ManagedRouteMBean> evaluator) { 091 if (this.evaluatorMap == null) { 092 this.evaluatorMap = new ConcurrentHashMap<>(); 093 } 094 095 this.evaluatorMap.computeIfAbsent(routeId, id -> new CopyOnWriteArrayList<>()).add(evaluator); 096 } 097 098 public Stream<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators() { 099 return this.evaluators != null 100 ? this.evaluators.stream() 101 : Stream.empty(); 102 } 103 104 public Stream<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators(String routeId) { 105 return this.evaluatorMap != null 106 ? evaluatorMap.getOrDefault(routeId, Collections.emptyList()).stream() 107 : Stream.empty(); 108 } 109 110 @Override 111 public Stream<HealthCheck> stream() { 112 // This is not really efficient as getRoutes() creates a copy of the routes 113 // array for each invocation. It would be nice to have more stream oriented 114 // operation on CamelContext i.e. 115 // 116 // interface CamelContext { 117 // 118 // Stream<Route> routes(); 119 // 120 // void forEachRoute(Consumer<Route> consumer); 121 // } 122 // 123 return this.context != null 124 ? this.context.getRoutes() 125 .stream() 126 .filter(route -> route.getId() != null) 127 .filter(route -> isNotBlacklisted(route)) 128 .map(this::toRouteHealthCheck) 129 : Stream.empty(); 130 } 131 132 // ***************************** 133 // Helpers 134 // ***************************** 135 136 private boolean isNotBlacklisted(Route route) { 137 return this.blacklist != null 138 ? !this.blacklist.contains(route.getId()) 139 : true; 140 } 141 142 private HealthCheck toRouteHealthCheck(Route route) { 143 return checks.computeIfAbsent( 144 route, 145 r -> { 146 HealthCheck check = new RouteHealthCheck( 147 route, 148 evaluatorMap != null 149 ? evaluatorMap.getOrDefault(r.getId(), evaluators) 150 : evaluators 151 ); 152 153 check.getConfiguration().setEnabled(true); 154 155 return check; 156 } 157 ); 158 } 159}