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