Move Category into data.msa package from ws.server to get it into min jabaws package.
[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 \r
61         /**\r
62          * Indicate whether the services were tested at all\r
63          */\r
64         private static boolean allTested = false;\r
65 \r
66         @Override\r
67         public Set<Services> getSupportedServices() {\r
68                 init();\r
69                 return operating.keySet();\r
70         }\r
71 \r
72         private void init() {\r
73                 // Do not allow tests to run concurrently\r
74                 if (timeToTest()) {\r
75                         synchronized (operating) {\r
76                                 if (timeToTest()) {\r
77                                         testAllServices();\r
78                                         allTested = true;\r
79                                 }\r
80                         }\r
81                 }\r
82         }\r
83 \r
84         private boolean timeToTest() {\r
85                 if (!allTested) {\r
86                         return true;\r
87                 }\r
88                 // 24 h\r
89                 if (getLongestUntestedServiceTime() > 3600 * 24) {\r
90                         return true;\r
91                 }\r
92                 return false;\r
93         }\r
94 \r
95         /**\r
96          * Return time in seconds for the test for the oldest unchecked service\r
97          * \r
98          * @return\r
99          */\r
100         private int getLongestUntestedServiceTime() {\r
101                 int timePassed = 0;\r
102                 for (Services serv : operating.keySet()) {\r
103                         int lasttimepassed = getLastTested(serv);\r
104                         if (timePassed < lasttimepassed) {\r
105                                 timePassed = lasttimepassed;\r
106                         }\r
107                 }\r
108                 return timePassed;\r
109         }\r
110 \r
111         @Override\r
112         public int getLastTested(Services service) {\r
113                 Date testedOn = getLastTestedOn(service);\r
114                 if (testedOn != null) {\r
115                         return (int) ((System.currentTimeMillis() - testedOn.getTime()) / 1000);\r
116                 }\r
117                 return 0;\r
118         }\r
119 \r
120         /**\r
121          * Can potentially return null if the service has not been tested yet.\r
122          */\r
123         @Override\r
124         public Date getLastTestedOn(Services service) {\r
125                 if (operating.containsKey(service)) {\r
126                         return operating.get(service);\r
127                 }\r
128                 return null;\r
129         }\r
130 \r
131         /**\r
132          * TODO improve reporting. stop testing service on unsupported runtime env\r
133          * exception\r
134          */\r
135         @Override\r
136         public String testAllServices() {\r
137                 Writer testlog = new StringWriter();\r
138                 PrintWriter writer = new PrintWriter(testlog, true);\r
139                 WSTester tester = new WSTester(getServicePath(), writer);\r
140                 // This is done deliberately to prevent malicious user from overloading\r
141                 // the server\r
142                 synchronized (operating) {\r
143                         for (Services service : Services.values()) {\r
144                                 try {\r
145                                         if (tester.checkService(service)) {\r
146                                                 operating.put(service, new Date());\r
147                                         }\r
148                                 } catch (Exception e) {\r
149                                         log.info(e, e.getCause());\r
150                                         writer.println("Fails to connect to a web service: "\r
151                                                         + service + " With " + e.getLocalizedMessage()\r
152                                                         + "\nDetails: ");\r
153                                         e.printStackTrace(writer);\r
154                                 }\r
155                         }\r
156                 }\r
157                 writer.close();\r
158                 return testlog.toString();\r
159         }\r
160 \r
161         private String getServicePath() {\r
162                 assert wsContext != null : "WS context injection failed!";\r
163                 MessageContext msContext = wsContext.getMessageContext();\r
164                 HttpServletRequest request = (HttpServletRequest) msContext\r
165                                 .get(MessageContext.SERVLET_REQUEST);\r
166 \r
167                 StringBuffer server = request.getRequestURL();\r
168                 server = server.delete(server.lastIndexOf("/"), server.length());\r
169                 return server.toString();\r
170         }\r
171 \r
172         @Override\r
173         public String testService(Services service) {\r
174                 String server = getServicePath();\r
175                 Writer testlog = new StringWriter();\r
176                 PrintWriter writer = new PrintWriter(testlog, true);\r
177                 WSTester tester = new WSTester(server, writer);\r
178                 try {\r
179                         synchronized (operating) {\r
180                                 boolean succeed = tester.checkService(service);\r
181                                 if (succeed) {\r
182                                         operating.put(service, new Date());\r
183                                 }\r
184                         }\r
185                 } catch (Exception e) {\r
186                         log.info(e, e.getCause());\r
187                         writer.println("Fails to connect to a web service: " + service\r
188                                         + " With " + e.getLocalizedMessage() + "\nDetails: ");\r
189                         e.printStackTrace(writer);\r
190                 } finally {\r
191                         writer.close();\r
192                 }\r
193                 return testlog.toString();\r
194         }\r
195         @Override\r
196         public boolean isOperating(Services service) {\r
197                 init();\r
198                 return operating.containsKey(service);\r
199         }\r
200 \r
201         @Override\r
202         public String getServiceDescription(Services service) {\r
203                 return service.getServiceInfo();\r
204         }\r
205 \r
206         @Override\r
207         public Set<Category> getServiceCategories() {\r
208                 return Category.getCategories();\r
209         }\r
210 \r
211 }\r