ae56e5b49b92d2855a1e3d030c675c0fed499e69
[jabaws.git] / webservices / compbio / ws / server / RegistryWS.java
1 package compbio.ws.server;\r
2 \r
3 import java.io.PrintWriter;\r
4 import java.io.StringWriter;\r
5 import java.io.Writer;\r
6 import java.util.Date;\r
7 import java.util.Map;\r
8 import java.util.Set;\r
9 import java.util.concurrent.ConcurrentHashMap;\r
10 \r
11 import javax.annotation.Resource;\r
12 import javax.jws.WebService;\r
13 import javax.servlet.http.HttpServletRequest;\r
14 import javax.xml.ws.WebServiceContext;\r
15 import javax.xml.ws.handler.MessageContext;\r
16 \r
17 import org.apache.log4j.Logger;\r
18 \r
19 import compbio.data.msa.JABAService;\r
20 import compbio.ws.client.Services;\r
21 import compbio.ws.client.WSTester;\r
22 \r
23 /**\r
24  * JABAWS services registry\r
25  * \r
26  * @author pvtroshin\r
27  * \r
28  */\r
29 @WebService(endpointInterface = "compbio.data.msa.RegistryWS", targetNamespace = JABAService.V2_SERVICE_NAMESPACE, serviceName = "RegistryWS")\r
30 public class RegistryWS implements compbio.data.msa.RegistryWS, JABAService {\r
31 \r
32         // Ask for resource injection\r
33         @Resource\r
34         WebServiceContext wsContext;\r
35 \r
36         private static Logger log = Logger.getLogger(RegistryWS.class);\r
37 \r
38         /**\r
39          * Stores tested and passed (the test) services and their testing time\r
40          */\r
41         private final static Map<Services, Date> operating = new ConcurrentHashMap<Services, Date>();\r
42 \r
43         /**\r
44          * Indicate whether the services were tested at all\r
45          */\r
46         private static boolean allTested = false;\r
47 \r
48         @Override\r
49         public Set<Services> getSupportedServices() {\r
50                 init();\r
51                 return operating.keySet();\r
52         }\r
53 \r
54         private void init() {\r
55                 // Do not allow tests to run concurrently\r
56                 if (timeToTest()) {\r
57                         synchronized (operating) {\r
58                                 if (timeToTest()) {\r
59                                         testAllServices();\r
60                                         allTested = true;\r
61                                 }\r
62                         }\r
63                 }\r
64         }\r
65 \r
66         private boolean timeToTest() {\r
67                 if (!allTested) {\r
68                         return true;\r
69                 }\r
70                 // 24 h\r
71                 if (getLongestUntestedServiceTime() > 3600 * 24) {\r
72                         return true;\r
73                 }\r
74                 return false;\r
75         }\r
76 \r
77         /**\r
78          * Return time in seconds for the test for the oldest unchecked service\r
79          * \r
80          * @return\r
81          */\r
82         private int getLongestUntestedServiceTime() {\r
83                 int timePassed = 0;\r
84                 for (Services serv : operating.keySet()) {\r
85                         int lasttimepassed = getLastTested(serv);\r
86                         if (timePassed < lasttimepassed) {\r
87                                 timePassed = lasttimepassed;\r
88                         }\r
89                 }\r
90                 return timePassed;\r
91         }\r
92 \r
93         @Override\r
94         public int getLastTested(Services service) {\r
95                 Date testedOn = getLastTestedOn(service);\r
96                 if (testedOn != null) {\r
97                         return (int) ((System.currentTimeMillis() - testedOn.getTime()) / 1000);\r
98                 }\r
99                 return 0;\r
100         }\r
101 \r
102         /**\r
103          * Can potentially return null if the service has not been tested yet.\r
104          */\r
105         @Override\r
106         public Date getLastTestedOn(Services service) {\r
107                 if (operating.containsKey(service)) {\r
108                         return operating.get(service);\r
109                 }\r
110                 return null;\r
111         }\r
112 \r
113         /**\r
114          * TODO improve reporting. stop testing service on unsupported runtime env\r
115          * exception\r
116          */\r
117         @Override\r
118         public String testAllServices() {\r
119                 Writer testlog = new StringWriter();\r
120                 PrintWriter writer = new PrintWriter(testlog, true);\r
121                 WSTester tester = new WSTester(getServicePath(), writer);\r
122                 // This is done deliberately to prevent malicious user from overloading\r
123                 // the server\r
124                 synchronized (operating) {\r
125                         for (Services service : Services.values()) {\r
126                                 try {\r
127                                         if (tester.checkService(service)) {\r
128                                                 operating.put(service, new Date());\r
129                                         }\r
130                                 } catch (Exception e) {\r
131                                         log.info(e, e.getCause());\r
132                                         writer.println("Fails to connect to a web service: "\r
133                                                         + service + " With " + e.getLocalizedMessage()\r
134                                                         + "\nDetails: ");\r
135                                         e.printStackTrace(writer);\r
136                                 }\r
137                         }\r
138                 }\r
139                 writer.close();\r
140                 return testlog.toString();\r
141         }\r
142 \r
143         private String getServicePath() {\r
144                 assert wsContext != null : "WS context injection failed!";\r
145                 MessageContext msContext = wsContext.getMessageContext();\r
146                 HttpServletRequest request = (HttpServletRequest) msContext\r
147                                 .get(MessageContext.SERVLET_REQUEST);\r
148 \r
149                 StringBuffer server = request.getRequestURL();\r
150                 server = server.delete(server.lastIndexOf("/"), server.length());\r
151                 return server.toString();\r
152         }\r
153 \r
154         @Override\r
155         public String testService(Services service) {\r
156                 String server = getServicePath();\r
157                 Writer testlog = new StringWriter();\r
158                 PrintWriter writer = new PrintWriter(testlog, true);\r
159                 WSTester tester = new WSTester(server, writer);\r
160                 try {\r
161                         synchronized (operating) {\r
162                                 boolean succeed = tester.checkService(service);\r
163                                 if (succeed) {\r
164                                         operating.put(service, new Date());\r
165                                 }\r
166                         }\r
167                 } catch (Exception e) {\r
168                         log.info(e, e.getCause());\r
169                         writer.println("Fails to connect to a web service: " + service\r
170                                         + " With " + e.getLocalizedMessage() + "\nDetails: ");\r
171                         e.printStackTrace(writer);\r
172                 } finally {\r
173                         writer.close();\r
174                 }\r
175                 return testlog.toString();\r
176         }\r
177         @Override\r
178         public boolean isOperating(Services service) {\r
179                 init();\r
180                 return operating.containsKey(service);\r
181         }\r
182 \r
183 }\r