JWS-121 Improved the AnnualStat and ServiceStatus classes so they start the scheduler...
[jabaws.git] / webservices / compbio / stat / servlet / ServiceStatus.java
1 /* Copyright (c) 2013 Alexander Sherstnev\r
2  * Copyright (c) 2011 Peter Troshin\r
3  *  \r
4  *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 2.0     \r
5  * \r
6  *  This library is free software; you can redistribute it and/or modify it under the terms of the\r
7  *  Apache License version 2 as published by the Apache Software Foundation\r
8  * \r
9  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\r
10  *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache \r
11  *  License for more details.\r
12  * \r
13  *  A copy of the license is in apache_license.txt. It is also available here:\r
14  * @see: http://www.apache.org/licenses/LICENSE-2.0.txt\r
15  * \r
16  * Any republication or derived work distributed in source code form\r
17  * must include this copyright and license notice.\r
18  */\r
19 \r
20 package compbio.stat.servlet;\r
21 \r
22 import java.io.IOException;\r
23 import java.io.PrintWriter;\r
24 import java.io.StringWriter;\r
25 import java.lang.management.ManagementFactory;\r
26 import java.net.InetAddress;\r
27 import java.net.UnknownHostException;\r
28 import java.util.*;\r
29 import java.net.*;\r
30 import java.text.SimpleDateFormat;\r
31 \r
32 import javax.management.AttributeNotFoundException;\r
33 import javax.management.InstanceNotFoundException;\r
34 import javax.management.MBeanException;\r
35 import javax.management.MBeanServer;\r
36 import javax.management.MalformedObjectNameException;\r
37 import javax.management.ObjectName;\r
38 import javax.management.Query;\r
39 import javax.management.ReflectionException;\r
40 import javax.servlet.RequestDispatcher;\r
41 import javax.servlet.ServletException;\r
42 import javax.servlet.http.HttpServlet;\r
43 import javax.servlet.http.HttpServletRequest;\r
44 import javax.servlet.http.HttpServletResponse;\r
45 \r
46 import compbio.engine.conf.PropertyHelperManager;\r
47 import compbio.stat.servlet.util.RefreshIterator;\r
48 import compbio.stat.servlet.util.Scheduler;\r
49 import compbio.stat.servlet.util.SchedulerTask;\r
50 import compbio.util.PropertyHelper;\r
51 import compbio.util.Util;\r
52 import org.apache.log4j.Logger;\r
53 \r
54 import compbio.ws.client.Services;\r
55 import compbio.ws.client.WSTester;\r
56 \r
57 /**\r
58  * Use cases:\r
59  * <dl>\r
60  * <li>Test web services and display results on the web page</li>\r
61  * </dl>\r
62  *\r
63  * @author pvtroshin\r
64  */\r
65 \r
66 public class ServiceStatus extends HttpServlet {\r
67 \r
68     private static final Logger log = Logger.getLogger(ServiceStatus.class);\r
69 \r
70     private static PropertyHelper ph = PropertyHelperManager.getPropertyHelper();\r
71 \r
72     private final Scheduler scheduler = new Scheduler();\r
73 \r
74     private List<String> getEndPoints() throws MalformedObjectNameException, NullPointerException, UnknownHostException,\r
75             AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException {\r
76         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();\r
77         Set<ObjectName> objs = mbs.queryNames(new ObjectName("*:type=Connector,*"),\r
78                 Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));\r
79         List<String> endPoints = new ArrayList<String>();\r
80         for (Iterator<ObjectName> i = objs.iterator(); i.hasNext(); ) {\r
81             ObjectName obj = i.next();\r
82             String scheme = mbs.getAttribute(obj, "scheme").toString();\r
83             String port = obj.getKeyProperty("port");\r
84             String hostname = InetAddress.getLocalHost().getHostName();\r
85             endPoints.add(scheme + "://" + hostname + ":" + port);\r
86         }\r
87         return endPoints;\r
88     }\r
89 \r
90     private static int getIntProperty(String propValue) {\r
91         int value = 0;\r
92         if (!Util.isEmpty(propValue)) {\r
93             propValue = propValue.trim();\r
94             value = Integer.parseInt(propValue);\r
95         }\r
96         return value;\r
97     }\r
98 \r
99     private static int refreshServiceStatusFrequency() {\r
100         return getIntProperty(ph.getProperty("local.service.status.refresh.frequency"));\r
101     }\r
102 \r
103     static int refreshUsageStatsFrequency() {\r
104         return getIntProperty(ph.getProperty("local.usage.stats.refresh.frequency"));\r
105     }\r
106 \r
107     @Override\r
108     public void init() {\r
109         // startup the scheduler with current time\r
110         int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);\r
111         int min = Calendar.getInstance().get(Calendar.MINUTE);\r
112         int sec = Calendar.getInstance().get(Calendar.SECOND);\r
113         // refresh sleep time (in between requests) - minutes\r
114         final int refresh_freq = refreshServiceStatusFrequency();\r
115 \r
116         scheduler.schedule(new SchedulerTask() {\r
117             public void run() {\r
118                 refreshCache();\r
119             }\r
120             private void refreshCache() {\r
121                 hitEndpointForRefresh();\r
122                 log.info("Refreshing the In Memory Cache...");\r
123                 log.info(String.format("Refreshing again in %d minutes", refresh_freq));\r
124             }\r
125         }, new RefreshIterator(hour, min, sec, refresh_freq));\r
126     }\r
127 \r
128     public void clearContextCache() {\r
129         // try remove the current values from the context\r
130         try {\r
131             this.getServletConfig().getServletContext().removeAttribute("serviceStatusResults");\r
132             this.getServletConfig().getServletContext().removeAttribute("serviceStatusTimestamp");\r
133             this.getServletConfig().getServletContext().removeAttribute("serviceStatusStart");\r
134             this.getServletConfig().getServletContext().removeAttribute("serviceStatusEnd");\r
135             this.getServletConfig().getServletContext().removeAttribute("serviceStatusAllGood");\r
136             log.info("In Memory Cache Cleared!");\r
137         } catch (Exception e) {\r
138             log.warn("In Memory Cache Not Cleared. Perhaps not available yet!");\r
139         }\r
140     }\r
141 \r
142     private void hitEndpointForRefresh() {\r
143         String endpointURL;\r
144         endpointURL = (String) this.getServletConfig().getServletContext().getAttribute("serviceStatusURL");\r
145         if (endpointURL != null){\r
146             try {\r
147                 URL url = new URL(endpointURL);\r
148                 System.out.println(endpointURL);\r
149                 HttpURLConnection connection = (HttpURLConnection) url.openConnection();\r
150                 connection.setRequestProperty("User-Agent", "JABAWS Service Status Refreshing the Context Cache");\r
151                 int status = connection.getResponseCode();\r
152                 log.info(String.format("Hitting %s with an internal user-agent! status code: %s",\r
153                         endpointURL, status));\r
154             } catch (IOException e) {\r
155                 log.warn("Something wrong when hitting " + endpointURL);\r
156                 log.warn(e);\r
157             }\r
158         }\r
159     }\r
160 \r
161     public ArrayList<ServiceTestResult> testServiceStatus(HttpServletRequest req) throws ServletException, IOException {\r
162 \r
163         ArrayList<ServiceTestResult> testResults = new ArrayList<ServiceTestResult>();\r
164 \r
165         // run the service status checkup\r
166         List<String> eps = new ArrayList<String>();\r
167         try {\r
168             eps = getEndPoints();\r
169         } catch (MalformedObjectNameException e) {\r
170             // TODO Auto-generated catch block\r
171             e.printStackTrace();\r
172         } catch (AttributeNotFoundException e) {\r
173             // TODO Auto-generated catch block\r
174             e.printStackTrace();\r
175         } catch (InstanceNotFoundException e) {\r
176             // TODO Auto-generated catch block\r
177             e.printStackTrace();\r
178         } catch (NullPointerException e) {\r
179             // TODO Auto-generated catch block\r
180             e.printStackTrace();\r
181         } catch (MBeanException e) {\r
182             // TODO Auto-generated catch block\r
183             e.printStackTrace();\r
184         } catch (ReflectionException e) {\r
185             // TODO Auto-generated catch block\r
186             e.printStackTrace();\r
187         }\r
188         if (1 != eps.size()) {\r
189             log.info(eps.size() + "EndPoints found");\r
190             //System.out.println("      " + eps.size() + " EndPoints found");\r
191             for (String endpoint : eps) {\r
192                 log.info(eps.size() + "EndPoint is " + endpoint);\r
193                 //System.out.println("   EndPoint is " + endpoint);\r
194             }\r
195         }\r
196 \r
197         String serverPath = new String();\r
198         for (String endpoint : eps) {\r
199             serverPath = endpoint + req.getContextPath();\r
200         }\r
201 \r
202         for (Services service : Services.values()) {\r
203             StringWriter testres = new StringWriter();\r
204             PrintWriter writer = new PrintWriter(testres, true);\r
205             WSTester tester = new WSTester(serverPath, writer);\r
206             ServiceTestResult result = new ServiceTestResult(service);\r
207             try {\r
208                 result.failed = tester.checkService(service);\r
209             } catch (Exception e) {\r
210                 log.info(e, e.getCause());\r
211                 String mess = "Fails to connect to the web service: " + service + ". Reason: ";\r
212                 writer.println(mess + e.getLocalizedMessage() + "\nDetails: ");\r
213                 e.printStackTrace(writer);\r
214             } finally {\r
215                 writer.close();\r
216             }\r
217             result.details = testres.toString();\r
218             testResults.add(result);\r
219         }\r
220         return testResults;\r
221     }\r
222 \r
223     public String overallStatusGood(ArrayList<ServiceTestResult> testResults) {\r
224         // assumes all good but returns as soon as some service is down\r
225         String success = "true";\r
226         for (int i = 0; i < testResults.size(); i++) {\r
227             if (!testResults.get(i).failed) {\r
228                 success = "false";\r
229                 break;\r
230             }\r
231         }\r
232         return success;\r
233     }\r
234 \r
235     @Override\r
236     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\r
237         /**\r
238          * // PROBLEM: the code tries to test not WS endpoints on an internal\r
239          * Tomcat, but on an external // endpoints with wrong info on the\r
240          * proxing StringBuffer jabawspath = req.getRequestURL(); jabawspath =\r
241          * jabawspath.delete(jabawspath.lastIndexOf("/"), jabawspath.length());\r
242          * String serverPath = jabawspath.toString();\r
243          */\r
244 \r
245         ArrayList<ServiceTestResult> testResults = new ArrayList<ServiceTestResult>();\r
246         String timeStamp = new String();\r
247         long startTime;\r
248         long endTime;\r
249         String refresh_freq;\r
250         String goodStatus;\r
251 \r
252         // save the main caller URL in the context\r
253         String url = new String();\r
254         url = req.getRequestURL().toString();\r
255         System.out.println("UR: " + url);\r
256         this.getServletConfig().getServletContext().setAttribute("serviceStatusURL", url);\r
257 \r
258         // check user-agent: this is a trick to get the cache refreshed periodically\r
259         String useragent = new String();\r
260         useragent = req.getHeader("user-agent");\r
261         // check if there are values available in the context\r
262         if (this.getServletConfig().getServletContext().getAttribute("serviceStatusResults") == null ||\r
263                 useragent.equals("JABAWS Service Status Refreshing the Context Cache")) {\r
264 \r
265             // test the services and timeit\r
266             startTime = System.nanoTime();\r
267             testResults = testServiceStatus(req);\r
268             endTime = System.nanoTime();\r
269             // try clear the previous values if any\r
270             clearContextCache();\r
271             // add the current values to the context\r
272             this.getServletConfig().getServletContext().setAttribute("serviceStatusResults", testResults);\r
273             timeStamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(\r
274                     Calendar.getInstance().getTime());\r
275             this.getServletConfig().getServletContext().setAttribute("serviceStatusTimestamp", timeStamp);\r
276             this.getServletConfig().getServletContext().setAttribute("serviceStatusStart", startTime);\r
277             this.getServletConfig().getServletContext().setAttribute("serviceStatusEnd", endTime);\r
278             refresh_freq = String.valueOf(refreshServiceStatusFrequency());\r
279             this.getServletConfig().getServletContext().setAttribute("serviceStatusRefreshFreq", refresh_freq);\r
280             goodStatus = overallStatusGood(testResults);\r
281             this.getServletConfig().getServletContext().setAttribute("serviceStatusAllGood", goodStatus);\r
282 \r
283         } else {\r
284             // get last results available\r
285             testResults = (ArrayList) this.getServletConfig().getServletContext().getAttribute("serviceStatusResults");\r
286             timeStamp = (String) this.getServletConfig().getServletContext().getAttribute("serviceStatusTimestamp");\r
287             startTime = (Long) this.getServletConfig().getServletContext().getAttribute("serviceStatusStart");\r
288             endTime = (Long) this.getServletConfig().getServletContext().getAttribute("serviceStatusEnd");\r
289             refresh_freq = (String) this.getServletConfig().getServletContext().getAttribute("serviceStatusRefreshFreq");\r
290         }\r
291 \r
292         req.setAttribute("results", testResults);\r
293         req.setAttribute("timestamp", timeStamp);\r
294         req.setAttribute("timeexec", (endTime - startTime) / 100000000);\r
295         req.setAttribute("refreshfreq", refresh_freq);\r
296         RequestDispatcher rd = req.getRequestDispatcher("statpages/ServicesStatus.jsp");\r
297         rd.forward(req, resp);\r
298     }\r
299 \r
300 }\r