Roll back some changes in WSDL of RegistryWS for some time: restore back compatibility
[jabaws.git] / webservices / compbio / ws / server / RegistryWS.java
1 /* Copyright (c) 2011 Peter Troshin\r
2  *  \r
3  *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 2.0     \r
4  * \r
5  *  This library is free software; you can redistribute it and/or modify it under the terms of the\r
6  *  Apache License version 2 as published by the Apache Software Foundation\r
7  * \r
8  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\r
9  *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache \r
10  *  License for more details.\r
11  * \r
12  *  A copy of the license is in apache_license.txt. It is also available here:\r
13  * @see: http://www.apache.org/licenses/LICENSE-2.0.txt\r
14  * \r
15  * Any republication or derived work distributed in source code form\r
16  * must include this copyright and license notice.\r
17  */\r
18 package compbio.ws.server;\r
19 \r
20 import java.io.PrintWriter;\r
21 import java.io.StringWriter;\r
22 import java.io.Writer;\r
23 import java.util.Date;\r
24 import java.util.Map;\r
25 import java.util.Set;\r
26 import java.util.concurrent.ConcurrentHashMap;\r
27 \r
28 import javax.annotation.Resource;\r
29 import javax.jws.WebService;\r
30 import javax.servlet.http.HttpServletRequest;\r
31 import javax.xml.ws.WebServiceContext;\r
32 import javax.xml.ws.handler.MessageContext;\r
33 \r
34 import org.apache.log4j.Logger;\r
35 \r
36 import compbio.data.msa.Category;\r
37 import compbio.data.msa.JABAService;\r
38 import compbio.ws.client.Services;\r
39 import compbio.ws.client.WSTester;\r
40 \r
41 /**\r
42  * JABAWS services registry\r
43  * \r
44  * @author pvtroshin\r
45  * \r
46  */\r
47 @WebService(endpointInterface = "compbio.data.msa.RegistryWS", targetNamespace = JABAService.V2_SERVICE_NAMESPACE, serviceName = "RegistryWS")\r
48 public class RegistryWS implements compbio.data.msa.RegistryWS, JABAService {\r
49 \r
50         // Ask for resource injection\r
51         @Resource\r
52         WebServiceContext wsContext;\r
53 \r
54         private static Logger log = Logger.getLogger(RegistryWS.class);\r
55 \r
56         /**\r
57          * Stores tested and passed (the test) services and their testing time\r
58          */\r
59         private final static Map<Services, Date> operating = new ConcurrentHashMap<Services, Date>();\r
60         private final static Map<Services, Date> nonoperating = new ConcurrentHashMap<Services, Date>();\r
61 \r
62         /**\r
63          * Indicate whether the services were tested at all\r
64          */\r
65         private static boolean allTested = false;\r
66 \r
67         @Override\r
68         public Set<Services> getSupportedServices() {\r
69                 init();\r
70                 return operating.keySet();\r
71         }\r
72 /* FOR FUTURE RELEASES!!!\r
73         @Override\r
74         public Set<Services> getNonoperatedServices() {\r
75                 init();\r
76                 return nonoperating.keySet();\r
77         }\r
78 */\r
79         private void init() {\r
80                 // Do not allow tests to run concurrently\r
81                 if (timeToTest()) {\r
82                         synchronized (operating) {\r
83                                 if (timeToTest()) {\r
84                                         testAllServices();\r
85                                         allTested = true;\r
86                                 }\r
87                         }\r
88                 }\r
89         }\r
90 \r
91         private boolean timeToTest() {\r
92                 if (!allTested) {\r
93                         return true;\r
94                 }\r
95                 // 24 h\r
96                 if (getLongestUntestedServiceTime() > 3600 * 24) {\r
97                         return true;\r
98                 }\r
99                 return false;\r
100         }\r
101 \r
102         /**\r
103          * Return time in seconds for the test for the oldest unchecked service\r
104          * \r
105          * @return\r
106          */\r
107         private int getLongestUntestedServiceTime() {\r
108                 int timePassed = 0;\r
109                 for (Services serv : operating.keySet()) {\r
110                         int lasttimepassed = getLastTested(serv);\r
111                         if (timePassed < lasttimepassed) {\r
112                                 timePassed = lasttimepassed;\r
113                         }\r
114                 }\r
115                 return timePassed;\r
116         }\r
117 \r
118         @Override\r
119         public int getLastTested(Services service) {\r
120                 Date testedOn = getLastTestedOn(service);\r
121                 if (testedOn != null) {\r
122                         return (int) ((System.currentTimeMillis() - testedOn.getTime()) / 1000);\r
123                 }\r
124                 return 0;\r
125         }\r
126 \r
127         /**\r
128          * Can potentially return null if the service has not been tested yet.\r
129          */\r
130         @Override\r
131         public Date getLastTestedOn(Services service) {\r
132                 if (operating.containsKey(service)) {\r
133                         return operating.get(service);\r
134                 }\r
135                 return null;\r
136         }\r
137 \r
138         /**\r
139          * TODO improve reporting. stop testing service on unsupported runtime env\r
140          * exception\r
141          */\r
142         @Override\r
143         public String testAllServices() {\r
144                 Writer testlog = new StringWriter();\r
145                 PrintWriter writer = new PrintWriter(testlog, true);\r
146                 WSTester tester = new WSTester(getServicePath(), writer);\r
147                 // This is done deliberately to prevent malicious user from overloading the server\r
148                 synchronized (operating) {\r
149                         for (Services service : Services.values()) {\r
150                                 try {\r
151                                         if (tester.checkService(service)) {\r
152                                                 operating.put(service, new Date());\r
153                                         } else {\r
154                                                 nonoperating.put(service, new Date());\r
155                                         }\r
156                                 } catch (Exception e) {\r
157                                         log.info(e, e.getCause());\r
158                                         String rep = "Fails to connect to a web service: " + service + " with";\r
159                                         writer.println(rep + e.getLocalizedMessage() + "\nDetails: ");\r
160                                         e.printStackTrace(writer);\r
161                                 }\r
162                         }\r
163                 }\r
164                 writer.close();\r
165                 return testlog.toString();\r
166         }\r
167 \r
168         private String getServicePath() {\r
169                 assert wsContext != null : "WS context injection failed!";\r
170                 MessageContext msContext = wsContext.getMessageContext();\r
171                 HttpServletRequest request = (HttpServletRequest) msContext.get(MessageContext.SERVLET_REQUEST);\r
172 \r
173                 StringBuffer server = request.getRequestURL();\r
174                 server = server.delete(server.lastIndexOf("/"), server.length());\r
175                 return server.toString();\r
176         }\r
177 \r
178         @Override\r
179         public String testService(Services service) {\r
180                 String server = getServicePath();\r
181                 Writer testlog = new StringWriter();\r
182                 PrintWriter writer = new PrintWriter(testlog, true);\r
183                 WSTester tester = new WSTester(server, writer);\r
184                 try {\r
185                         synchronized (operating) {\r
186                                 boolean succeed = tester.checkService(service);\r
187                                 if (succeed) {\r
188                                         operating.put(service, new Date());\r
189                                 }\r
190                         }\r
191                 } catch (Exception e) {\r
192                         log.info(e, e.getCause());\r
193                         writer.println("Fails to connect to a web service: " + service\r
194                                         + " With " + e.getLocalizedMessage() + "\nDetails: ");\r
195                         e.printStackTrace(writer);\r
196                 } finally {\r
197                         writer.close();\r
198                 }\r
199                 return testlog.toString();\r
200         }\r
201         @Override\r
202         public boolean isOperating(Services service) {\r
203                 init();\r
204                 return operating.containsKey(service);\r
205         }\r
206 \r
207         @Override\r
208         public String getServiceDescription(Services service) {\r
209                 return service.getServiceInfo();\r
210         }\r
211 \r
212         @Override\r
213         public Set<Category> getServiceCategories() {\r
214                 return Category.getCategories();\r
215         }\r
216 \r
217 }\r