1919import  java .io .IOException ;
2020
2121import  jakarta .servlet .ServletException ;
22+ import  jakarta .servlet .http .HttpServletResponse ;
2223
24+ import  org .apache .catalina .Container ;
2325import  org .apache .catalina .Context ;
2426import  org .apache .catalina .LifecycleException ;
2527import  org .apache .catalina .connector .Request ;
2628import  org .apache .catalina .connector .Response ;
29+ import  org .apache .catalina .util .LifecycleBase ;
2730import  org .apache .tomcat .util .buf .MessageBytes ;
2831
2932
@@ -38,13 +41,24 @@ public class HealthCheckValve extends ValveBase {
3841            "  \" checks\" : []\n "  +
3942            "}" ;
4043
44+     private  static  final  String  DOWN  =
45+             "{\n "  +
46+             "  \" status\" : \" DOWN\" ,\n "  +
47+             "  \" checks\" : []\n "  +
48+             "}" ;
49+ 
4150    private  String  path  = "/health" ;
4251
4352    /** 
4453     * Will be set to true if the valve is associated with a context. 
4554     */ 
4655    protected  boolean  context  = false ;
4756
57+     /** 
58+      * Check if all child containers are available. 
59+      */ 
60+     protected  boolean  checkContainersAvailable  = true ;
61+ 
4862    public  HealthCheckValve () {
4963        super (true );
5064    }
@@ -57,6 +71,14 @@ public final void setPath(String path) {
5771        this .path  = path ;
5872    }
5973
74+     public  boolean  getCheckContainersAvailable () {
75+         return  this .checkContainersAvailable ;
76+     }
77+ 
78+     public  void  setCheckContainersAvailable (boolean  checkContainersAvailable ) {
79+         this .checkContainersAvailable  = checkContainersAvailable ;
80+     }
81+ 
6082    @ Override 
6183    protected  synchronized  void  startInternal () throws  LifecycleException  {
6284        super .startInternal ();
@@ -74,9 +96,28 @@ public void invoke(Request request, Response response)
7496                context  ? request .getRequestPathMB () : request .getDecodedRequestURIMB ();
7597        if  (urlMB .equals (path )) {
7698            response .setContentType ("application/json" );
77-             response .getOutputStream ().print (UP );
99+             if  (isAvailable (getContainer ())) {
100+                 response .getOutputStream ().print (UP );
101+             } else  {
102+                 response .setStatus (HttpServletResponse .SC_SERVICE_UNAVAILABLE );
103+                 response .getOutputStream ().print (DOWN );
104+             }
78105        } else  {
79106            getNext ().invoke (request , response );
80107        }
81108    }
109+ 
110+     protected  boolean  isAvailable (Container  container ) {
111+         for  (Container  child  : container .findChildren ()) {
112+             if  (!isAvailable (child )) {
113+                 return  false ;
114+             }
115+         }
116+         if  (container  instanceof  LifecycleBase ) {
117+             return  ((LifecycleBase ) container ).getState ().isAvailable ();
118+         } else  {
119+             return  true ;
120+         }
121+     }
122+ 
82123}
0 commit comments