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.util.Collection;
020import java.util.Collections;
021import java.util.Optional;
022
023import javax.management.openmbean.CompositeData;
024import javax.management.openmbean.CompositeDataSupport;
025import javax.management.openmbean.CompositeType;
026import javax.management.openmbean.TabularData;
027import javax.management.openmbean.TabularDataSupport;
028
029import org.apache.camel.CamelContext;
030import org.apache.camel.RuntimeCamelException;
031import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
032import org.apache.camel.api.management.mbean.ManagedCamelHealthMBean;
033import org.apache.camel.health.HealthCheck;
034import org.apache.camel.health.HealthCheckHelper;
035import org.apache.camel.health.HealthCheckRegistry;
036import org.apache.camel.health.HealthCheckRepository;
037import org.apache.camel.spi.ManagementStrategy;
038import org.apache.camel.support.ExceptionHelper;
039
040public class ManagedCamelHealth implements ManagedCamelHealthMBean {
041    private final CamelContext context;
042    private final HealthCheckRegistry healthCheckRegistry;
043
044    public ManagedCamelHealth(CamelContext context, HealthCheckRegistry healthCheckRegistry) {
045        this.context = context;
046        this.healthCheckRegistry = healthCheckRegistry;
047    }
048
049    public void init(ManagementStrategy strategy) {
050        // do nothing
051    }
052
053    public CamelContext getContext() {
054        return context;
055    }
056
057    @Override
058    public boolean isEnabled() {
059        return healthCheckRegistry.isEnabled();
060    }
061
062    @Override
063    public boolean isHealthy() {
064        for (HealthCheck.Result result : HealthCheckHelper.invoke(context)) {
065            if (result.getState() == HealthCheck.State.DOWN) {
066                return false;
067            }
068        }
069
070        return true;
071    }
072
073    @Override
074    public boolean isHealthyReadiness() {
075        for (HealthCheck.Result result : HealthCheckHelper.invokeReadiness(context)) {
076            if (result.getState() == HealthCheck.State.DOWN) {
077                return false;
078            }
079        }
080
081        return true;
082    }
083
084    @Override
085    public boolean isHealthyLiveness() {
086        for (HealthCheck.Result result : HealthCheckHelper.invokeLiveness(context)) {
087            if (result.getState() == HealthCheck.State.DOWN) {
088                return false;
089            }
090        }
091
092        return true;
093    }
094
095    @Override
096    public Collection<String> getHealthChecksIDs() {
097        return healthCheckRegistry.getCheckIDs();
098    }
099
100    @Override
101    public TabularData details() {
102        try {
103            final TabularData answer = new TabularDataSupport(CamelOpenMBeanTypes.camelHealthDetailsTabularType());
104            final CompositeType type = CamelOpenMBeanTypes.camelHealthDetailsCompositeType();
105
106            for (HealthCheck.Result result : HealthCheckHelper.invoke(context)) {
107                String failureUri = (String) result.getDetails().getOrDefault(HealthCheck.ENDPOINT_URI, "");
108                Integer failureCount = (Integer) result.getDetails().getOrDefault(HealthCheck.FAILURE_COUNT, 0);
109
110                String stacktrace = "";
111                if (result.getError().isPresent()) {
112                    stacktrace = ExceptionHelper.stackTraceToString(result.getError().get());
113                }
114
115                CompositeData data = new CompositeDataSupport(
116                        type,
117                        new String[] {
118                                "id",
119                                "group",
120                                "state",
121                                "enabled",
122                                "message",
123                                "failureUri",
124                                "failureCount",
125                                "failureStackTrace",
126                                "readiness",
127                                "liveness"
128                        },
129                        new Object[] {
130                                result.getCheck().getId(),
131                                result.getCheck().getGroup(),
132                                result.getState().name(),
133                                result.getCheck().isEnabled(),
134                                result.getMessage().orElse(""),
135                                failureUri,
136                                failureCount,
137                                stacktrace,
138                                result.getCheck().isReadiness(),
139                                result.getCheck().isLiveness()
140                        });
141
142                answer.put(data);
143            }
144
145            return answer;
146        } catch (Exception e) {
147            throw RuntimeCamelException.wrapRuntimeCamelException(e);
148        }
149    }
150
151    @Override
152    public String invoke(String id) {
153        Optional<HealthCheck.Result> result = HealthCheckHelper.invoke(context, id, Collections.emptyMap());
154
155        return result.map(r -> r.getState().name()).orElse(HealthCheck.State.UNKNOWN.name());
156    }
157
158    @Override
159    public void enableById(String id) {
160        Optional<HealthCheck> hc = healthCheckRegistry.getCheck(id);
161        if (hc.isPresent()) {
162            hc.get().setEnabled(true);
163        } else {
164            Optional<HealthCheckRepository> hcr = healthCheckRegistry.getRepository(id);
165            hcr.ifPresent(repository -> repository.setEnabled(true));
166        }
167    }
168
169    @Override
170    public void disableById(String id) {
171        Optional<HealthCheck> hc = healthCheckRegistry.getCheck(id);
172        if (hc.isPresent()) {
173            hc.get().setEnabled(false);
174        } else {
175            Optional<HealthCheckRepository> hcr = healthCheckRegistry.getRepository(id);
176            hcr.ifPresent(repository -> repository.setEnabled(false));
177        }
178    }
179}