recover original data for tree and pca as alignment view.
[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  * DOCUMENT ME!\r
35  *\r
36  * @author $author$\r
37  * @version $Revision$\r
38  */\r
39 public class MsaWSClient\r
40     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   AlignFrame alignFrame;\r
47 \r
48 \r
49   /**\r
50    * Creates a new MsaWSClient object that uses a service\r
51    * given by an externally retrieved ServiceHandle\r
52    *\r
53    * @param sh service handle of type AbstractName(MsaWS)\r
54    * @param altitle DOCUMENT ME!\r
55    * @param msa DOCUMENT ME!\r
56    * @param submitGaps DOCUMENT ME!\r
57    * @param preserveOrder DOCUMENT ME!\r
58    */\r
59 \r
60   public MsaWSClient(ext.vamsas.ServiceHandle sh, String altitle,\r
61                      jalview.datamodel.AlignmentView msa,\r
62                      boolean submitGaps, boolean preserveOrder,\r
63                      Alignment seqdataset,\r
64                      AlignFrame _alignFrame)\r
65   {\r
66 \r
67     alignFrame = _alignFrame;\r
68     if (!sh.getAbstractName().equals("MsaWS"))\r
69     {\r
70       JOptionPane.showMessageDialog(Desktop.desktop,\r
71                                     "The Service called \n" + sh.getName() +\r
72           "\nis not a \nMultiple Sequence Alignment Service !",\r
73                                     "Internal Jalview Error",\r
74                                     JOptionPane.WARNING_MESSAGE);\r
75 \r
76       return;\r
77     }\r
78 \r
79     if ((wsInfo = this.setWebService(sh))==null)\r
80      {\r
81        JOptionPane.showMessageDialog(Desktop.desktop,\r
82                                      "The Multiple Sequence Alignment Service named " +\r
83                                      sh.getName() +\r
84                                      " is unknown", "Internal Jalview Error",\r
85                                      JOptionPane.WARNING_MESSAGE);\r
86 \r
87        return;\r
88      }\r
89     startMsaWSClient(altitle, msa, submitGaps, preserveOrder, seqdataset);\r
90 \r
91   }\r
92 \r
93 \r
94   private void startMsaWSClient(String altitle, AlignmentView msa,\r
95                      boolean submitGaps, boolean preserveOrder, Alignment seqdataset)\r
96   {\r
97     if (!locateWebService())\r
98     {\r
99       return;\r
100     }\r
101 \r
102     wsInfo.setProgressText( ( (submitGaps) ? "Re-alignment" : "Alignment") +\r
103                            " of " + altitle + "\nJob details\n");\r
104 \r
105     MsaWSThread musclethread = new MsaWSThread(WebServiceName +\r
106                                                " alignment of " + altitle, msa,\r
107                                                submitGaps, preserveOrder, seqdataset);\r
108     wsInfo.setthisService(musclethread);\r
109     musclethread.start();\r
110   }\r
111 \r
112   /**\r
113    * Initializes the server field with a valid service implementation.\r
114    *\r
115    * @return true if service was located.\r
116    */\r
117   private boolean locateWebService()\r
118   {\r
119     // TODO: MuscleWS transmuted to generic MsaWS client\r
120     MuscleWSServiceLocator loc = new MuscleWSServiceLocator(); // Default\r
121 \r
122     try\r
123     {\r
124       this.server = (MuscleWS) loc.getMuscleWS(new java.net.URL(WsURL));\r
125       ( (MuscleWSSoapBindingStub)this.server).setTimeout(60000); // One minute timeout\r
126     }\r
127     catch (Exception ex)\r
128     {\r
129       wsInfo.setProgressText("Serious! " + WebServiceName +\r
130                              " Service location failed\nfor URL :" + WsURL +\r
131                              "\n" +\r
132                              ex.getMessage());\r
133       wsInfo.setStatus(WebserviceInfo.ERROR);\r
134       ex.printStackTrace();\r
135 \r
136       return false;\r
137     }\r
138 \r
139     loc.getEngine().setOption("axis", "1");\r
140 \r
141     return true;\r
142   }\r
143 \r
144   protected String getServiceActionKey()\r
145   {\r
146     return "MsaWS";\r
147   }\r
148 \r
149   protected String getServiceActionDescription()\r
150   {\r
151     return "Multiple Sequence Alignment";\r
152   }\r
153 \r
154   protected class MsaWSThread\r
155       extends Thread implements WSClientI\r
156   {\r
157     String ServiceName = WebServiceName;\r
158     String OutputHeader;\r
159     vamsas.objects.simple.MsaResult result = null;\r
160     vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.\r
161         SequenceSet();\r
162     Hashtable SeqNames = null;\r
163     boolean submitGaps = false; // pass sequences including gaps to alignment service\r
164     boolean preserveOrder = true; // and always store and recover sequence order\r
165     String jobId;\r
166     String alTitle; // name which will be used to form new alignment window.\r
167     int allowedServerExceptions = 3; // thread dies if too many exceptions.\r
168     boolean jobComplete = false;\r
169 \r
170     Alignment dataset; // dataset to which the new alignment will be associated.\r
171 \r
172     MsaWSThread(String title, AlignmentView _msa, boolean subgaps,\r
173                 boolean presorder, Alignment seqset)\r
174     {\r
175       // jbpnote - transformation should be above here - this is per sequence set contig, not for many contigs.\r
176       alTitle = title;\r
177       submitGaps = subgaps;\r
178       preserveOrder = presorder;\r
179       dataset = seqset;\r
180       OutputHeader = wsInfo.getProgressText();\r
181       SeqNames = new Hashtable();\r
182       SeqCigar[] msa = _msa.getSequences();\r
183       vamsas.objects.simple.Sequence[] seqarray = new vamsas.objects.simple.\r
184           Sequence[msa.length];\r
185 \r
186       for (int i = 0,n=0; i < msa.length; i++)\r
187       {\r
188         String newname = jalview.analysis.SeqsetUtils.unique_name(i);\r
189         SequenceI mseq = msa[i].getSeq('-');\r
190         // uniquify as we go\r
191         // TODO: JBPNote: this is a ubiquitous transformation - set of jalview seq objects to vamsas sequences with name preservation\r
192         SeqNames.put(newname,\r
193                      jalview.analysis.SeqsetUtils.SeqCharacterHash(mseq));\r
194         seqarray[i] = new vamsas.objects.simple.Sequence();\r
195         seqarray[i].setId(newname);\r
196         seqarray[i].setSeq( (submitGaps) ? mseq.getSequence()\r
197                            : AlignSeq.extractGaps(\r
198                                jalview.util.Comparison.GapChars,\r
199                                mseq.getSequence()));\r
200       }\r
201 \r
202       this.seqs = new vamsas.objects.simple.SequenceSet();\r
203       this.seqs.setSeqs(seqarray);\r
204     }\r
205 \r
206     public boolean isCancellable()\r
207     {\r
208       return true;\r
209     }\r
210 \r
211     public void cancelJob()\r
212     {\r
213       if ( (jobId != null) && !jobId.equals("") && !jobComplete)\r
214       {\r
215         String cancelledMessage = "";\r
216 \r
217         try\r
218         {\r
219           vamsas.objects.simple.WsJobId cancelledJob = server.cancel(jobId);\r
220 \r
221           if (cancelledJob.getStatus() == 2)\r
222           {\r
223             // CANCELLED_JOB\r
224             cancelledMessage = "Job cancelled.";\r
225             wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);\r
226             jobComplete = true;\r
227             jobsRunning--;\r
228             result = null;\r
229           }\r
230           else if (cancelledJob.getStatus() == 3)\r
231           {\r
232             // VALID UNSTOPPABLE JOB\r
233             cancelledMessage +=\r
234                 "Server cannot cancel this job. just close the window.\n";\r
235           }\r
236 \r
237           if (cancelledJob.getJobId() != null)\r
238           {\r
239             cancelledMessage += ("[" + cancelledJob.getJobId() +\r
240                                  "]");\r
241           }\r
242 \r
243           cancelledMessage += "\n";\r
244         }\r
245         catch (Exception exc)\r
246         {\r
247           cancelledMessage +=\r
248               ("\nProblems cancelling the job : Exception received...\n" +\r
249                exc + "\n");\r
250           exc.printStackTrace();\r
251         }\r
252 \r
253         wsInfo.setProgressText(OutputHeader + cancelledMessage + "\n");\r
254       }\r
255       else\r
256       {\r
257         if (!jobComplete)\r
258         {\r
259           wsInfo.setProgressText(OutputHeader +\r
260                                  "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");\r
261         }\r
262       }\r
263     }\r
264 \r
265     public void run()\r
266     {\r
267       StartJob();\r
268 \r
269       while (!jobComplete && (allowedServerExceptions > 0))\r
270       {\r
271         try\r
272         {\r
273           if ( (result = server.getResult(jobId)) == null)\r
274           {\r
275             throw (new Exception(\r
276                 "Timed out when communicating with server\nTry again later.\n"));\r
277           }\r
278           jalview.bin.Cache.log.debug("Result state " + result.getState() +\r
279                                         "(ServerError=" + result.isServerError() +\r
280                                         ")");\r
281           if (result.isRunning())\r
282           {\r
283             wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);\r
284           }\r
285           else if (result.isQueued())\r
286           {\r
287             wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);\r
288           }\r
289 \r
290           if (result.isFinished())\r
291           {\r
292             wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
293             wsInfo.showResultsNewFrame.addActionListener(new java.awt.event.ActionListener()\r
294                 {\r
295                   public void actionPerformed(java.awt.event.ActionEvent evt)\r
296                   {\r
297                     displayResults(true);\r
298                   }\r
299                 });\r
300            wsInfo.mergeResults.addActionListener(new java.awt.event.ActionListener()\r
301                 {\r
302                   public void actionPerformed(java.awt.event.ActionEvent evt)\r
303                   {\r
304                     displayResults(false);\r
305                   }\r
306                 });\r
307            wsInfo.setResultsReady();\r
308             parseResult();\r
309             jobComplete = true;\r
310             jobsRunning--;\r
311           }\r
312           else\r
313           {\r
314             if (result.getStatus() != null)\r
315             {\r
316               wsInfo.setProgressText(OutputHeader + "\n"+   result.getStatus());\r
317             }\r
318             if (result.isServerError())\r
319             {\r
320               jobComplete = true;\r
321               jobsRunning--;\r
322 \r
323               break;\r
324             }\r
325             if (! (result.isJobFailed() || result.isServerError() ||\r
326                    result.isBroken() || result.isFailed()))\r
327             {\r
328               Thread.sleep(5000);\r
329 \r
330               //  System.out.println("I'm alive "+seqid+" "+jobid);\r
331             }\r
332             else\r
333             {\r
334               jobComplete = true;\r
335               jobsRunning--;\r
336               break;\r
337             }\r
338           }\r
339         }\r
340         catch (Exception ex)\r
341         {\r
342           allowedServerExceptions--;\r
343           wsInfo.appendProgressText("\n" + ServiceName +\r
344                                     " Server exception!\n" + ex.getMessage());\r
345           System.err.println(ServiceName + " Server exception: " +\r
346                              ex.getMessage());\r
347 \r
348           //          ex.printStackTrace(); JBPNote Debug\r
349           try\r
350           {\r
351             if (allowedServerExceptions > 0)\r
352             {\r
353               Thread.sleep(5000);\r
354             }\r
355           }\r
356           catch (InterruptedException ex1)\r
357           {\r
358           }\r
359         }\r
360         catch(OutOfMemoryError er)\r
361         {\r
362           jobComplete = true;\r
363           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
364           JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
365               "Out of memory handling result!!"\r
366              +"\nSee help files for increasing Java Virtual Machine memory."\r
367              ,"Out of memory", JOptionPane.WARNING_MESSAGE );\r
368           System.out.println("MsaWSClient: "+er);\r
369           System.gc();\r
370         }\r
371       }\r
372 \r
373       if (allowedServerExceptions == 0)\r
374       {\r
375         wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
376       }\r
377       else\r
378       {\r
379         if (result != null)\r
380         {\r
381           if ( !(result.isJobFailed() || result.isServerError()))\r
382           {\r
383             wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
384           }\r
385 \r
386           if (result.isBroken() || result.isFailed())\r
387           {\r
388             wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
389           }\r
390 \r
391           if (result.isServerError())\r
392           {\r
393             wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
394           }\r
395         }\r
396       }\r
397     }\r
398 \r
399     void StartJob()\r
400     {\r
401       try\r
402       {\r
403         vamsas.objects.simple.WsJobId jobsubmit = server.align(seqs);\r
404 \r
405         if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))\r
406         {\r
407           jobId = jobsubmit.getJobId();\r
408           System.out.println(WsURL + " Job Id '" + jobId + "'");\r
409         }\r
410         else\r
411         {\r
412           if (jobsubmit == null)\r
413           {\r
414             throw new Exception("Server at " + WsURL +\r
415                                 " returned null object, it probably cannot be contacted. Try again later ?");\r
416           }\r
417 \r
418           throw new Exception(jobsubmit.getJobId());\r
419         }\r
420       }\r
421       catch (Exception e)\r
422       {\r
423         // TODO: JBPNote catch timeout or other fault types explicitly\r
424         // For unexpected errors\r
425         System.err.println(WebServiceName +\r
426                            "Client: Failed to submit the sequences for alignment (probably a server side problem)\n" +\r
427                            "When contacting Server:" + WsURL + "\n" +\r
428                            e.toString() +\r
429                            "\n");\r
430         this.allowedServerExceptions = 0;\r
431         wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
432         wsInfo.appendProgressText(\r
433             "Failed to submit sequences for alignment.\n" +\r
434             "It is most likely that there is a problem with the server.\n" +\r
435             "Just close the window\n");\r
436 \r
437         // e.printStackTrace(); // TODO: JBPNote DEBUG\r
438       }\r
439     }\r
440 \r
441     private jalview.datamodel.Sequence[] getVamsasAlignment(\r
442         vamsas.objects.simple.Alignment valign)\r
443     {\r
444       vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();\r
445       jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.\r
446           length];\r
447 \r
448       for (int i = 0, j = seqs.length; i < j; i++)\r
449       {\r
450         msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),\r
451                                                 seqs[i].getSeq());\r
452       }\r
453 \r
454       return msa;\r
455     }\r
456 \r
457     void parseResult()\r
458     {\r
459 \r
460       try\r
461       {\r
462         // OutputHeader = output.getText();\r
463         if (result.isFailed())\r
464         {\r
465           OutputHeader += "Job failed.\n";\r
466         }\r
467 \r
468         if (result.getStatus() != null)\r
469         {\r
470           OutputHeader += ("\n" + result.getStatus());\r
471         }\r
472 \r
473         if (result.getMsa() != null)\r
474         {\r
475           OutputHeader += "\nAlignment Object Method Notes\n";\r
476 \r
477           String[] lines = result.getMsa().getMethod();\r
478 \r
479           for (int line = 0; line < lines.length; line++)\r
480           {\r
481             OutputHeader += (lines[line] + "\n");\r
482           }\r
483 \r
484           // JBPNote The returned files from a webservice could be\r
485           // hidden behind icons in the monitor window that,\r
486           // when clicked, pop up their corresponding data\r
487         }\r
488 \r
489         wsInfo.setProgressText(OutputHeader);\r
490       }\r
491       catch (Exception ex)\r
492       {\r
493         ex.printStackTrace();\r
494       }\r
495     }\r
496 \r
497     void displayResults(boolean newFrame)\r
498     {\r
499       SequenceI [] seqs = getVamsasAlignment(result.getMsa());\r
500 \r
501       if (seqs != null)\r
502        {\r
503          AlignmentOrder msaorder = new AlignmentOrder(seqs);\r
504 \r
505          if (preserveOrder)\r
506          {\r
507            jalview.analysis.AlignmentSorter.recoverOrder(seqs);\r
508          }\r
509 \r
510          jalview.analysis.SeqsetUtils.deuniquify(SeqNames, seqs);\r
511 \r
512          Alignment al = new Alignment(seqs);\r
513          if (dataset!=null)\r
514          {\r
515            al.setDataset(dataset);\r
516          }\r
517 \r
518          if(newFrame)\r
519          {\r
520            // TODO: JBPNote Should also rename the query sequence sometime...\r
521            AlignFrame af = new AlignFrame(al);\r
522 \r
523          //>>>This is a fix for the moment, until a better solution is found!!<<<\r
524            af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());\r
525 \r
526            af.addSortByOrderMenuItem(ServiceName + " Ordering",\r
527                                      msaorder);\r
528 \r
529            Desktop.addInternalFrame(af, alTitle,\r
530                                     AlignFrame.NEW_WINDOW_WIDTH,\r
531                                     AlignFrame.NEW_WINDOW_HEIGHT);\r
532 \r
533          }\r
534          else\r
535          {\r
536            System.out.println("MERGE WITH OLD FRAME");\r
537 \r
538          }\r
539        }\r
540     }\r
541   }\r
542 }\r