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