Formatting changes
[jalview.git] / src / jalview / ws / MsaWSClient.java
1 /*\r
2 * Jalview - A Sequence Alignment Editor and Viewer\r
3 * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4 *\r
5 * This program is free software; you can redistribute it and/or\r
6 * modify it under the terms of the GNU General Public License\r
7 * as published by the Free Software Foundation; either version 2\r
8 * of the License, or (at your option) any later version.\r
9 *\r
10 * This program is distributed in the hope that it will be useful,\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 * GNU General Public License for more details.\r
14 *\r
15 * You should have received a copy of the GNU General Public License\r
16 * along with this program; if not, write to the Free Software\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18 */\r
19 package jalview.ws;\r
20 \r
21 import ext.vamsas.*;\r
22 \r
23 import jalview.analysis.AlignSeq;\r
24 \r
25 import jalview.datamodel.*;\r
26 \r
27 import jalview.gui.*;\r
28 \r
29 import java.util.*;\r
30 \r
31 import javax.swing.*;\r
32 \r
33 \r
34 /**\r
35  * DOCUMENT ME!\r
36  *\r
37  * @author $author$\r
38  * @version $Revision$\r
39  */\r
40 public class MsaWSClient extends WSClient\r
41 {\r
42     /**\r
43     * server is a WSDL2Java generated stub for an archetypal MsaWSI service.\r
44     */\r
45     ext.vamsas.MuscleWS server;\r
46 \r
47     /**\r
48      * Creates a new MsaWSClient object.\r
49      *\r
50      * @param MsaWSName DOCUMENT ME!\r
51      * @param altitle DOCUMENT ME!\r
52      * @param msa DOCUMENT ME!\r
53      * @param submitGaps DOCUMENT ME!\r
54      * @param preserveOrder DOCUMENT ME!\r
55      */\r
56     public MsaWSClient(String MsaWSName, String altitle, SequenceI[] msa,\r
57         boolean submitGaps, boolean preserveOrder)\r
58     {\r
59         if (setWebService(MsaWSName) == false)\r
60         {\r
61             JOptionPane.showMessageDialog(Desktop.desktop,\r
62                 "The Multiple Sequence Alignment Service named " + MsaWSName +\r
63                 " is unknown", "Internal Jalview Error",\r
64                 JOptionPane.WARNING_MESSAGE);\r
65 \r
66             return;\r
67         }\r
68 \r
69         wsInfo = new jalview.gui.WebserviceInfo(WebServiceJobTitle,\r
70                 WebServiceReference);\r
71 \r
72         if (!locateWebService())\r
73         {\r
74             return;\r
75         }\r
76 \r
77         wsInfo.setProgressText(((submitGaps) ? "Re-alignment" : "Alignment") +\r
78             " of " + altitle + "\nJob details\n");\r
79 \r
80         MsaWSThread musclethread = new MsaWSThread(WebServiceName +\r
81                 " alignment of " + altitle, msa, submitGaps, preserveOrder);\r
82         wsInfo.setthisService(musclethread);\r
83         musclethread.start();\r
84     }\r
85 \r
86     // JBPNote Nasty object-global state setting methods shouldn't be allowed\r
87     private boolean setWebService(String MsaWSName)\r
88     {\r
89         if (MsaWServices.info.containsKey(MsaWSName))\r
90         {\r
91             WebServiceName = MsaWSName;\r
92 \r
93             String[] wsinfo = (String[]) MsaWServices.info.get(MsaWSName);\r
94             WsURL = wsinfo[0];\r
95             WebServiceJobTitle = wsinfo[1];\r
96             WebServiceReference = wsinfo[2];\r
97 \r
98             return true;\r
99         }\r
100         else\r
101         {\r
102             return false;\r
103         }\r
104     }\r
105 \r
106     /**\r
107      * DOCUMENT ME!\r
108      *\r
109      * @return DOCUMENT ME!\r
110      */\r
111     private boolean locateWebService()\r
112     {\r
113         // TODO: MuscleWS transmuted to generic MsaWS client\r
114         MuscleWSServiceLocator loc = new MuscleWSServiceLocator(); // Default\r
115 \r
116         try\r
117         {\r
118             this.server = (MuscleWS) loc.getMuscleWS(new java.net.URL(WsURL));\r
119             ((MuscleWSSoapBindingStub) this.server).setTimeout(60000); // One minute timeout\r
120         }\r
121         catch (Exception ex)\r
122         {\r
123             wsInfo.setProgressText("Serious! " + WebServiceName +\r
124                 " Service location failed\nfor URL :" + WsURL + "\n" +\r
125                 ex.getMessage());\r
126             wsInfo.setStatus(wsInfo.ERROR);\r
127             ex.printStackTrace();\r
128 \r
129             return false;\r
130         }\r
131 \r
132         loc.getEngine().setOption("axis", "1");\r
133 \r
134         return true;\r
135     }\r
136 \r
137     protected class MsaWSThread extends Thread implements WSClientI\r
138     {\r
139         String ServiceName = WebServiceName;\r
140         String OutputHeader;\r
141         vamsas.objects.simple.MsaResult result = null;\r
142         vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();\r
143         Hashtable SeqNames = null;\r
144         boolean submitGaps = false; // and always store and recover sequence order\r
145         boolean preserveOrder = true; // and always store and recover sequence order\r
146         String jobId;\r
147         String alTitle; // name which will be used to form new alignment window.\r
148         int allowedServerExceptions = 3; // thread dies if too many exceptions.\r
149         boolean jobComplete = false;\r
150 \r
151         MsaWSThread(String title, SequenceI[] msa, boolean subgaps,\r
152             boolean presorder)\r
153         {\r
154             alTitle = title;\r
155             submitGaps = subgaps;\r
156             preserveOrder = presorder;\r
157 \r
158             OutputHeader = wsInfo.getProgressText();\r
159             SeqNames = new Hashtable();\r
160 \r
161             vamsas.objects.simple.Sequence[] seqarray = new vamsas.objects.simple.Sequence[msa.length];\r
162 \r
163             for (int i = 0; i < msa.length; i++)\r
164             {\r
165                 String newname = jalview.analysis.SeqsetUtils.unique_name(i);\r
166 \r
167                 // uniquify as we go\r
168                 // TODO: JBPNote: this is a ubiquitous transformation - set of jalview seq objects to vamsas sequences with name preservation\r
169                 SeqNames.put(newname,\r
170                     jalview.analysis.SeqsetUtils.SeqCharacterHash(msa[i]));\r
171                 seqarray[i] = new vamsas.objects.simple.Sequence();\r
172                 seqarray[i].setId(newname);\r
173                 seqarray[i].setSeq((submitGaps) ? msa[i].getSequence()\r
174                                                 : AlignSeq.extractGaps(\r
175                         jalview.util.Comparison.GapChars, msa[i].getSequence()));\r
176             }\r
177 \r
178             this.seqs = new vamsas.objects.simple.SequenceSet();\r
179             this.seqs.setSeqs(seqarray);\r
180         }\r
181 \r
182         public boolean isCancellable()\r
183         {\r
184             return true;\r
185         }\r
186 \r
187         public void cancelJob()\r
188         {\r
189             if ((jobId != null) && !jobId.equals("") && !jobComplete)\r
190             {\r
191                 String cancelledMessage = "";\r
192 \r
193                 try\r
194                 {\r
195                     vamsas.objects.simple.WsJobId cancelledJob = server.cancel(jobId);\r
196 \r
197                     if (cancelledJob.getStatus() == 2)\r
198                     {\r
199                         // CANCELLED_JOB\r
200                         cancelledMessage = "Job cancelled.";\r
201                         wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);\r
202                         jobComplete = true;\r
203                         jobsRunning--;\r
204                         result = null;\r
205                     }\r
206                     else if (cancelledJob.getStatus() == 3)\r
207                     {\r
208                         // VALID UNSTOPPABLE JOB\r
209                         cancelledMessage += "Server cannot cancel this job. just close the window.\n";\r
210                     }\r
211 \r
212                     if (cancelledJob.getJobId() != null)\r
213                     {\r
214                         cancelledMessage += ("[" + cancelledJob.getJobId() +\r
215                         "]");\r
216                     }\r
217 \r
218                     cancelledMessage += "\n";\r
219                 }\r
220                 catch (Exception exc)\r
221                 {\r
222                     cancelledMessage += ("\nProblems cancelling the job : Exception received...\n" +\r
223                     exc + "\n");\r
224                     exc.printStackTrace();\r
225                 }\r
226 \r
227                 wsInfo.setProgressText(OutputHeader + cancelledMessage + "\n");\r
228             }\r
229             else\r
230             {\r
231                 if (!jobComplete)\r
232                 {\r
233                     wsInfo.setProgressText(OutputHeader +\r
234                         "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");\r
235                 }\r
236             }\r
237         }\r
238 \r
239         public void run()\r
240         {\r
241             StartJob();\r
242 \r
243             while (!jobComplete && (allowedServerExceptions > 0))\r
244             {\r
245                 try\r
246                 {\r
247                     if ((result = server.getResult(jobId)) == null)\r
248                     {\r
249                         throw (new Exception(\r
250                             "Timed out when communicating with server\nTry again later.\n"));\r
251                     }\r
252 \r
253                     if (result.isRunning())\r
254                     {\r
255                         wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);\r
256                     }\r
257                     else if (result.isQueued())\r
258                     {\r
259                         wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);\r
260                     }\r
261 \r
262                     if (result.isFinished())\r
263                     {\r
264                         parseResult();\r
265                         jobComplete = true;\r
266                         jobsRunning--;\r
267                     }\r
268                     else\r
269                     {\r
270                         if (result.getStatus() != null)\r
271                         {\r
272                             wsInfo.setProgressText(OutputHeader + "\n" +\r
273                                 result.getStatus());\r
274                         }\r
275 \r
276                         if (!(result.isJobFailed() || result.isServerError()))\r
277                         {\r
278                             Thread.sleep(5000);\r
279 \r
280                             //  System.out.println("I'm alive "+seqid+" "+jobid);\r
281                         }\r
282                         else\r
283                         {\r
284                             break;\r
285                         }\r
286                     }\r
287                 }\r
288                 catch (Exception ex)\r
289                 {\r
290                     allowedServerExceptions--;\r
291                     wsInfo.appendProgressText("\n" + ServiceName +\r
292                         " Server exception!\n" + ex.getMessage());\r
293                     System.err.println(ServiceName + " Server exception: " +\r
294                         ex.getMessage());\r
295 \r
296                     //          ex.printStackTrace(); JBPNote Debug\r
297                     try\r
298                     {\r
299                         if (allowedServerExceptions > 0)\r
300                         {\r
301                             Thread.sleep(5000);\r
302                         }\r
303                     }\r
304                     catch (InterruptedException ex1)\r
305                     {\r
306                     }\r
307                 }\r
308             }\r
309 \r
310             if (allowedServerExceptions == 0)\r
311             {\r
312                 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
313             }\r
314             else\r
315             {\r
316                 if (!((result != null) &&\r
317                         (result.isJobFailed() || result.isServerError())))\r
318                 {\r
319                     wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
320                 }\r
321                 else\r
322                 {\r
323                     if (result.isFailed())\r
324                     {\r
325                         wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
326                     }\r
327 \r
328                     if (result.isServerError())\r
329                     {\r
330                         wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
331                     }\r
332                 }\r
333             }\r
334         }\r
335 \r
336         void StartJob()\r
337         {\r
338             try\r
339             {\r
340                 vamsas.objects.simple.WsJobId jobsubmit = server.align(seqs);\r
341 \r
342                 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))\r
343                 {\r
344                     jobId = jobsubmit.getJobId();\r
345                     System.out.println(WsURL + " Job Id '" + jobId + "'");\r
346                 }\r
347                 else\r
348                 {\r
349                     if (jobsubmit == null)\r
350                     {\r
351                         throw new Exception("Server at " + WsURL +\r
352                             " returned null object, it probably cannot be contacted. Try again later ?");\r
353                     }\r
354 \r
355                     throw new Exception(jobsubmit.getJobId());\r
356                 }\r
357             }\r
358             catch (Exception e)\r
359             {\r
360                 // TODO: JBPNote catch timeout or other fault types explicitly\r
361                 // For unexpected errors\r
362                 System.err.println(WebServiceName +\r
363                     "Client: Failed to submit the sequences for alignment (probably a server side problem)\n" +\r
364                     "When contacting Server:" + WsURL + "\n" + e.toString() +\r
365                     "\n");\r
366                 this.allowedServerExceptions = 0;\r
367                 wsInfo.setStatus(wsInfo.STATE_STOPPED_SERVERERROR);\r
368                 wsInfo.appendProgressText(\r
369                     "Failed to submit sequences for alignment.\n" +\r
370                     "It is most likely that there is a problem with the server.\n" +\r
371                     "Just close the window\n");\r
372 \r
373                 // e.printStackTrace(); // TODO: JBPNote DEBUG\r
374             }\r
375         }\r
376 \r
377         private void addFloatAnnotations(Alignment al, int[] gapmap,\r
378             Vector values, String Symname, String Visname, float min,\r
379             float max, int winLength)\r
380         {\r
381             Annotation[] annotations = new Annotation[al.getWidth()];\r
382 \r
383             for (int j = 0; j < values.size(); j++)\r
384             {\r
385                 float value = Float.parseFloat(values.get(j).toString());\r
386                 annotations[gapmap[j]] = new Annotation("", value + "", ' ',\r
387                         value);\r
388             }\r
389 \r
390             al.addAnnotation(new AlignmentAnnotation(Symname, Visname,\r
391                     annotations, min, max, winLength));\r
392         }\r
393 \r
394         private jalview.datamodel.Sequence[] getVamsasAlignment(\r
395             vamsas.objects.simple.Alignment valign)\r
396         {\r
397             vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();\r
398             jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];\r
399 \r
400             for (int i = 0, j = seqs.length; i < j; i++)\r
401                 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),\r
402                         seqs[i].getSeq());\r
403 \r
404             return msa;\r
405         }\r
406 \r
407         void parseResult()\r
408         {\r
409             SequenceI[] seqs = null;\r
410 \r
411             try\r
412             {\r
413                 // OutputHeader = output.getText();\r
414                 if (result.isFailed())\r
415                 {\r
416                     OutputHeader += "Job failed.\n";\r
417                 }\r
418 \r
419                 if (result.getStatus() != null)\r
420                 {\r
421                     OutputHeader += ("\n" + result.getStatus());\r
422                 }\r
423 \r
424                 if (result.getMsa() != null)\r
425                 {\r
426                     OutputHeader += "\nAlignment Object Method Notes\n";\r
427 \r
428                     String[] lines = result.getMsa().getMethod();\r
429 \r
430                     for (int line = 0; line < lines.length; line++)\r
431                         OutputHeader += (lines[line] + "\n");\r
432 \r
433                     // JBPNote The returned files from a webservice could be hidden behind icons in the monitor window that, when clicked, pop up their corresponding data\r
434                     seqs = getVamsasAlignment(result.getMsa());\r
435                 }\r
436 \r
437                 wsInfo.setProgressText(OutputHeader);\r
438 \r
439                 if (seqs != null)\r
440                 {\r
441                     AlignmentOrder msaorder = new AlignmentOrder(seqs);\r
442 \r
443                     if (preserveOrder)\r
444                     {\r
445                         jalview.analysis.AlignmentSorter.recoverOrder(seqs);\r
446                     }\r
447 \r
448                     jalview.analysis.SeqsetUtils.deuniquify(SeqNames, seqs);\r
449 \r
450                     Alignment al = new Alignment(seqs);\r
451 \r
452                     // TODO: JBPNote Should also rename the query sequence sometime...\r
453                     AlignFrame af = new AlignFrame(al);\r
454                     af.addSortByOrderMenuItem(ServiceName + " Ordering",\r
455                         msaorder);\r
456 \r
457                     Desktop.addInternalFrame(af, alTitle,\r
458                         AlignFrame.NEW_WINDOW_WIDTH,\r
459                         AlignFrame.NEW_WINDOW_HEIGHT);\r
460                 }\r
461             }\r
462             catch (Exception ex)\r
463             {\r
464                 ex.printStackTrace();\r
465             }\r
466         }\r
467     }\r
468 }\r