package org.gcube.smartgears.extensions.resource; import static org.gcube.smartgears.Constants.application_json; import static org.gcube.smartgears.extensions.HttpExtension.Method.GET; import java.io.IOException; import java.io.PrintWriter; import java.util.Set; import java.util.Timer; import java.util.stream.Collectors; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; import org.gcube.common.health.api.HealthCheck; import org.gcube.common.health.api.ReadinessChecker; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.extensions.ApiResource; import org.gcube.smartgears.extensions.ApiSignature; import org.gcube.smartgears.health.HealthManager; import org.gcube.smartgears.health.HealthResponse; import org.gcube.smartgears.health.HealthTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ClassInfoList; import io.github.classgraph.ScanResult; public class HealthResource extends ApiResource { private static final long serialVersionUID = 1L; private static Logger log = LoggerFactory.getLogger(HealthResource.class); public static final String mapping = "/health"; private static final ApiSignature signature = handles(mapping).with(method(GET).produces(application_json)); private HealthManager manager; private HealthTask task; private Timer timer; HealthResource() { super(signature); } @Override public void init(ApplicationContext context) throws Exception { Set> annotatedReadiness; try (ScanResult result = new ClassGraph().enableClassInfo().enableAnnotationInfo().scan()) { ClassInfoList classInfos = result.getClassesWithAnnotation(ReadinessChecker.class.getName()); annotatedReadiness = classInfos.stream().map(ClassInfo::loadClass) .filter(c -> HealthCheck.class.isAssignableFrom(c)).collect(Collectors.toSet()); } manager = new HealthManager(); for (Class readnessClass : annotatedReadiness) try { manager.register((HealthCheck) readnessClass.getDeclaredConstructor().newInstance()); log.info("added class {} to health manager", readnessClass.getCanonicalName()); } catch (Throwable e) { log.error("healthChecker class {} cannot be instantiated", readnessClass.getCanonicalName(), e); } task = new HealthTask(manager); timer = new Timer(true); timer.scheduleAtFixedRate(task, 10000, 60000); super.init(context); } public void stop() { if (timer!=null) timer.cancel(); } @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); resp.setContentType("application/json"); resp.setCharacterEncoding("UTF-8"); HealthResponse response = readiness(); new ObjectMapper().writeValue(out, response); out.flush(); } public HealthResponse readiness() { return task.getResponse(); } }