After merge
[jalview.git] / src / jalview / ws / JPredClient.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 java.util.*;\r
22 \r
23 import javax.swing.*;\r
24 \r
25 import ext.vamsas.*;\r
26 import jalview.analysis.*;\r
27 import jalview.datamodel.*;\r
28 import jalview.gui.*;\r
29 import jalview.io.FormatAdapter;\r
30 \r
31 public class JPredClient\r
32     extends WSClient\r
33 {\r
34   ext.vamsas.Jpred server;\r
35   String altitle = "";\r
36   java.util.Hashtable SequenceInfo = null;\r
37   public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI seq) {\r
38     wsInfo = setWebService(sh);\r
39     startJPredClient(title, seq);\r
40   }\r
41   public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI[] msa) {\r
42     wsInfo = setWebService(sh);\r
43     startJPredClient(title, msa);\r
44   }\r
45 \r
46   public JPredClient(String title, SequenceI[] msf) {\r
47     startJPredClient(title, msf);\r
48   }\r
49 \r
50   public JPredClient(String title, SequenceI seq) {\r
51     startJPredClient(title, seq);\r
52   }\r
53 \r
54   private void startJPredClient(String title, SequenceI[] msf)\r
55   {\r
56     if (wsInfo==null)\r
57       wsInfo = setWebService();\r
58 \r
59     SequenceI seq = msf[0];\r
60 \r
61     altitle = "JNet prediction on " + seq.getName() +\r
62         " using alignment from " + title;\r
63 \r
64     wsInfo.setProgressText("Job details for MSA based prediction (" +\r
65                            title + ") on sequence :\n>" + seq.getName() + "\n" +\r
66                            AlignSeq.extractGaps("-. ", seq.getSequence()) +\r
67                            "\n");\r
68     SequenceI aln[] = new SequenceI[msf.length];\r
69     for (int i=0,j=msf.length; i<j;i++) {\r
70         aln[i] = new jalview.datamodel.Sequence(msf[i]);\r
71     }\r
72 \r
73     SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true);\r
74 \r
75     if (!locateWebService())\r
76     {\r
77       return;\r
78     }\r
79 \r
80     JPredThread jthread = new JPredThread(aln);\r
81     jthread.start();\r
82   }\r
83 \r
84   public void startJPredClient(String title, SequenceI seq)\r
85   {\r
86     if (wsInfo==null)\r
87       wsInfo = setWebService();\r
88     wsInfo.setProgressText("Job details for prediction on sequence :\n>" +\r
89                            seq.getName() + "\n" +\r
90                            AlignSeq.extractGaps("-. ", seq.getSequence()) +\r
91                            "\n");\r
92     altitle = "JNet prediction for sequence " + seq.getName() + " from " +\r
93         title;\r
94 \r
95     SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash(seq);\r
96 \r
97     if (!locateWebService())\r
98     {\r
99       return;\r
100     }\r
101 \r
102     JPredThread jthread = new JPredThread(seq);\r
103     jthread.start();\r
104   }\r
105 \r
106   private WebserviceInfo setWebService()\r
107   {\r
108     WebServiceName = "JNetWS";\r
109     WebServiceJobTitle = "JNet secondary structure prediction";\r
110     WebServiceReference =\r
111         "\"Cuff J. A and Barton G.J (1999) Application of enhanced " +\r
112         "multiple sequence alignment profiles to improve protein secondary structure prediction, " +\r
113         "Proteins 40:502-511\".";\r
114     WsURL = "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred";\r
115 \r
116     WebserviceInfo wsInfo = new WebserviceInfo(WebServiceJobTitle,\r
117                                                WebServiceReference);\r
118 \r
119     return wsInfo;\r
120   }\r
121 \r
122   private boolean locateWebService()\r
123   {\r
124     ext.vamsas.JpredServiceLocator loc = new JpredServiceLocator(); // Default\r
125 \r
126     try\r
127     {\r
128       this.server = loc.getjpred(new java.net.URL(WsURL)); // JBPNote will be set from properties\r
129       ( (JpredSoapBindingStub)this.server).setTimeout(60000); // one minute stub\r
130     }\r
131     catch (Exception ex)\r
132     {\r
133       JOptionPane.showMessageDialog(Desktop.desktop,\r
134                                     "The Secondary Structure Prediction Service named " +\r
135                                     WebServiceName + " at " + WsURL +\r
136                                     " couldn't be located.",\r
137                                     "Internal Jalview Error",\r
138                                     JOptionPane.WARNING_MESSAGE);\r
139       wsInfo.setProgressText("Serious! " + WebServiceName +\r
140                              " Service location failed\nfor URL :" + WsURL +\r
141                              "\n" +\r
142                              ex.getMessage());\r
143       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
144 \r
145       return false;\r
146     }\r
147 \r
148     return true;\r
149   }\r
150 \r
151   class JPredThread\r
152       extends Thread\r
153   {\r
154     String OutputHeader;\r
155     vamsas.objects.simple.JpredResult result;\r
156     vamsas.objects.simple.Sequence sequence;\r
157     vamsas.objects.simple.Msfalignment msa;\r
158     String jobId;\r
159     boolean jobComplete = false;\r
160     int allowedServerExceptions = 3; // thread dies if too many exceptions.\r
161 \r
162     JPredThread(SequenceI seq)\r
163     {\r
164       OutputHeader = wsInfo.getProgressText();\r
165       this.sequence = new vamsas.objects.simple.Sequence();\r
166       this.sequence.setId(seq.getName());\r
167       this.sequence.setSeq(AlignSeq.extractGaps("-. ", seq.getSequence()));\r
168     }\r
169 \r
170     JPredThread(SequenceI[] msf)\r
171     {\r
172       OutputHeader = wsInfo.getProgressText();\r
173       this.sequence = new vamsas.objects.simple.Sequence();\r
174       this.sequence.setId(msf[0].getName());\r
175       this.sequence.setSeq(AlignSeq.extractGaps("-. ",\r
176                                                 msf[0].getSequence()));\r
177 \r
178       this.msa = new vamsas.objects.simple.Msfalignment();\r
179       jalview.io.PileUpfile pileup = new jalview.io.PileUpfile();\r
180       msa.setMsf(pileup.print(msf));\r
181     }\r
182 \r
183     public void run()\r
184     {\r
185       StartJob();\r
186 \r
187       while (!jobComplete && (allowedServerExceptions > 0))\r
188       {\r
189         try\r
190         {\r
191           if ( (result = server.getresult(jobId)) == null)\r
192           {\r
193             throw (new Exception(\r
194                 "Timed out when communicating with server\nTry again later.\n"));\r
195           }\r
196           if (result.getState()==0)\r
197             jalview.bin.Cache.log.debug("Finished "+jobId);\r
198           if (result.isRunning())\r
199           {\r
200             wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);\r
201           }\r
202           if (result.isQueued())\r
203           {\r
204             wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);\r
205           }\r
206 \r
207           wsInfo.setProgressText(OutputHeader + "\n" +\r
208                                  result.getStatus());\r
209 \r
210           if (result.isFinished())\r
211           {\r
212 \r
213             parseResult();\r
214             jobComplete = true;\r
215             jobsRunning--;\r
216           } else {\r
217             // catch exceptions\r
218             if (! (result.isJobFailed() || result.isServerError()))\r
219             {\r
220               try\r
221               {\r
222                 Thread.sleep(5000);\r
223               }\r
224               catch (InterruptedException ex1)\r
225               {\r
226               }\r
227 \r
228               //  System.out.println("I'm alive "+seqid+" "+jobid);\r
229             }\r
230             else\r
231             {\r
232               wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
233               jobsRunning--;\r
234               jobComplete = true;\r
235             }\r
236           }\r
237         }\r
238         catch (Exception ex)\r
239         {\r
240           allowedServerExceptions--;\r
241           wsInfo.appendProgressText("\nJPredWS Server exception!\n" +\r
242                                     ex.getMessage());\r
243 \r
244           try\r
245           {\r
246             if (allowedServerExceptions > 0)\r
247             {\r
248               Thread.sleep(5000);\r
249             }\r
250           }\r
251           catch (InterruptedException ex1)\r
252           {\r
253           }\r
254         }\r
255         catch (OutOfMemoryError er)\r
256         {\r
257           jobComplete = true;\r
258           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
259           JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
260                                                 "Out of memory handling result!!"\r
261                                                 +\r
262               "\nSee help files for increasing Java Virtual Machine memory."\r
263                                                 , "Out of memory",\r
264                                                 JOptionPane.WARNING_MESSAGE);\r
265           System.out.println("JPredClient: "+er);\r
266           System.gc();\r
267         }\r
268       }\r
269       if (result!=null)\r
270         if (! (result.isJobFailed() || result.isServerError()))\r
271         {\r
272           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
273         }\r
274         else\r
275         {\r
276           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
277         }\r
278     }\r
279 \r
280     void StartJob()\r
281     {\r
282       try\r
283       {\r
284         if (msa != null)\r
285         {\r
286           jobId = server.predictOnMsa(msa);\r
287         }\r
288         else\r
289         {\r
290           jobId = server.predict(sequence);\r
291         }\r
292 \r
293         if (jobId != null)\r
294         {\r
295           if (jobId.startsWith("Broken"))\r
296           {\r
297             throw new Exception("Submission " + jobId);\r
298           }\r
299           else\r
300           {\r
301             System.out.println(WsURL + " Job Id '" + jobId + "'");\r
302           }\r
303         }\r
304         else\r
305         {\r
306           throw new Exception("Server timed out - try again later\n");\r
307         }\r
308       }\r
309       catch (Exception e)\r
310       {\r
311         if (e.getMessage().indexOf("Exception")>-1) {\r
312           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
313           wsInfo.setProgressText(\r
314               "Failed to submit the prediction. (Just close the window)\n"\r
315               +\r
316               "It is most likely that there is a problem with the server.\n");\r
317           System.err.println(\r
318               "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" +\r
319               e.getMessage() + "\n");\r
320 \r
321           jalview.bin.Cache.log.warn("Server Exception",e);\r
322         } else {\r
323           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
324           // JBPNote - this could be a popup informing the user of the problem.\r
325           wsInfo.setProgressText("Failed to submit the prediction:\n"\r
326                                  +e.getMessage()+\r
327                                  wsInfo.getProgressText());\r
328 \r
329           jalview.bin.Cache.log.debug("Failed Submission",e);\r
330 \r
331         }\r
332         allowedServerExceptions = -1;\r
333         jobComplete = true;\r
334 \r
335       }\r
336     }\r
337 \r
338 \r
339 \r
340   /*  private void addFloatAnnotations(Alignment al, int[] gapmap,\r
341                                      Vector values, String Symname,\r
342                                      String Visname, float min,\r
343                                      float max, int winLength)\r
344     {\r
345       Annotation[] annotations = new Annotation[al.getWidth()];\r
346 \r
347       for (int j = 0; j < values.size(); j++)\r
348       {\r
349         float value = Float.parseFloat(values.get(j).toString());\r
350         annotations[gapmap[j]] = new Annotation("", value + "", ' ',\r
351                                                 value);\r
352       }\r
353 \r
354       al.addAnnotation(new AlignmentAnnotation(Symname, Visname,\r
355                                                annotations, min, max, winLength));\r
356     }*/\r
357 \r
358     void parseResult()\r
359     {\r
360       // OutputHeader = output.getText();\r
361       if (result.isFailed())\r
362       {\r
363         OutputHeader += "Job failed.\n";\r
364       }\r
365 \r
366       if (result.getStatus() != null)\r
367       {\r
368         OutputHeader += ("\n" + result.getStatus());\r
369       }\r
370 \r
371       if (result.getPredfile() != null)\r
372       {\r
373         OutputHeader += ("\n" + result.getPredfile());\r
374 \r
375         // 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
376       }\r
377 \r
378       if (result.getAligfile() != null)\r
379       {\r
380         OutputHeader += ("\n" + result.getAligfile());\r
381       }\r
382 \r
383       wsInfo.setProgressText(OutputHeader+"Parsing...");\r
384 \r
385       try\r
386       {\r
387         jalview.bin.Cache.log.debug("Parsing output from JNet job.");\r
388         // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File");\r
389         jalview.io.JPredFile prediction = new jalview.io.JPredFile(result.\r
390             getPredfile(),\r
391             "Paste");\r
392         SequenceI[] preds = prediction.getSeqsAsArray();\r
393         jalview.bin.Cache.log.debug("Got prediction profile.");\r
394         Alignment al;\r
395         int FirstSeq; // the position of the query sequence in Alignment al\r
396         boolean noMsa = true; // set if no MSA has been returned by JPred\r
397 \r
398         if ( (this.msa != null) && (result.getAligfile() != null))\r
399         {\r
400           jalview.bin.Cache.log.debug("Getting associated alignment.");\r
401           // we ignore the returned alignment if we only predicted on a single sequence\r
402           String format = jalview.io.IdentifyFile.Identify(result.getAligfile(),\r
403               "Paste");\r
404 \r
405           if (jalview.io.FormatAdapter.formats.contains(format))\r
406           {\r
407             al = new Alignment(new FormatAdapter().readFile(\r
408                 result.getAligfile(), "Paste", format));\r
409             SequenceI sqs[] = new SequenceI[al.getHeight()];\r
410             for (int i=0, j=al.getHeight(); i<j; i++) {\r
411               sqs[i] = al.getSequenceAt(i);\r
412             }\r
413             if (!jalview.analysis.SeqsetUtils.deuniquify(\r
414                   (Hashtable) SequenceInfo,sqs))\r
415               {\r
416                 throw (new Exception(\r
417                     "Couldn't recover sequence properties for alignment."));\r
418               }\r
419 \r
420             noMsa = false;\r
421             FirstSeq = 0;\r
422           }\r
423           else\r
424           {\r
425             throw (new Exception(\r
426                 "Unknown format 'format' for file : \n" +\r
427                 result.getAligfile()));\r
428           }\r
429         }\r
430         else\r
431         {\r
432           al = new Alignment(preds);\r
433           FirstSeq = prediction.getQuerySeqPosition();\r
434           if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(\r
435               al.getSequenceAt(FirstSeq), SequenceInfo))\r
436           {\r
437             throw (new Exception(\r
438                 "Couldn't recover sequence properties for JNet Query sequence!"));\r
439           }\r
440         }\r
441 \r
442 \r
443         AlignmentAnnotation annot;\r
444         Annotation[] annotations = null;\r
445         int i = 0;\r
446         int width = preds[0].getSequence().length();\r
447 \r
448         int[] gapmap = al.getSequenceAt(FirstSeq).gapMap();\r
449 \r
450         if (gapmap.length != width)\r
451         {\r
452           throw (new Exception(\r
453               "Jnet Client Error\nNumber of residues in supposed query sequence :\n" +\r
454               al.getSequenceAt(FirstSeq).getName() + "\n" +\r
455               al.getSequenceAt(FirstSeq).getSequence() +\r
456               "\nDiffer from number of prediction sites in \n" +\r
457               result.getPredfile() + "\n"));\r
458         }\r
459 \r
460         // JBPNote Should also rename the query sequence sometime...\r
461         i = 0;\r
462 \r
463         while (i < preds.length)\r
464         {\r
465           String id = preds[i].getName().toUpperCase();\r
466 \r
467           if (id.startsWith("LUPAS") || id.startsWith("JNET") ||\r
468               id.startsWith("JPRED"))\r
469           {\r
470             annotations = new Annotation[al.getWidth()];\r
471 \r
472             if (id.equals("JNETPRED") || id.equals("JNETPSSM") ||\r
473                 id.equals("JNETFREQ") || id.equals("JNETHMM") ||\r
474                 id.equals("JNETALIGN") || id.equals("JPRED"))\r
475             {\r
476               for (int j = 0; j < width; j++)\r
477               {\r
478                 annotations[gapmap[j]] = new Annotation("", "",\r
479                     preds[i].getCharAt(j), 0);\r
480               }\r
481             }\r
482             else if (id.equals("JNETCONF"))\r
483             {\r
484               for (int j = 0; j < width; j++)\r
485               {\r
486                 float value = Float.parseFloat(preds[i].getCharAt(\r
487                     j) + "");\r
488                 annotations[gapmap[j]] = new Annotation(preds[i].getCharAt(\r
489                     j) + "", "", preds[i].getCharAt(j),\r
490                     value);\r
491               }\r
492             }\r
493             else\r
494             {\r
495               for (int j = 0; j < width; j++)\r
496               {\r
497                 annotations[gapmap[j]] = new Annotation(preds[i].getCharAt(\r
498                     j) + "", "", ' ', 0);\r
499               }\r
500             }\r
501 \r
502             if (id.equals("JNETCONF"))\r
503             {\r
504               annot = new AlignmentAnnotation(preds[i].getName(),\r
505                                               "JNet Output", annotations, 0f,\r
506                                               10f, 1);\r
507             }\r
508             else\r
509             {\r
510               annot = new AlignmentAnnotation(preds[i].getName(),\r
511                                               "JNet Output", annotations);\r
512             }\r
513 \r
514             al.addAnnotation(annot);\r
515 \r
516             if (noMsa)\r
517             {\r
518               al.deleteSequence(preds[i]);\r
519             }\r
520           }\r
521 \r
522           i++;\r
523         }\r
524 \r
525         //Hashtable scores = prediction.getScores();\r
526 \r
527         /*  addFloatAnnotations(al, gapmap,  (Vector)scores.get("JNETPROPH"),\r
528                               "JnetpropH", "Jnet Helix Propensity", 0f,1f,1);\r
529 \r
530           addFloatAnnotations(al, gapmap,  (Vector)scores.get("JNETPROPB"),\r
531          "JnetpropB", "Jnet Beta Sheet Propensity", 0f,1f,1);\r
532 \r
533           addFloatAnnotations(al, gapmap,  (Vector)scores.get("JNETPROPC"),\r
534                               "JnetpropC", "Jnet Coil Propensity", 0f,1f,1);\r
535          */\r
536 \r
537         wsInfo.setProgressText(OutputHeader);\r
538         jalview.bin.Cache.log.debug("Finished parsing output.");\r
539         AlignFrame af = new AlignFrame(al);\r
540 \r
541         Desktop.addInternalFrame(af, altitle,\r
542                                  AlignFrame.NEW_WINDOW_WIDTH,\r
543                                  AlignFrame.NEW_WINDOW_HEIGHT);\r
544       }\r
545       catch (Exception ex)\r
546       {\r
547         jalview.bin.Cache.log.warn("Exception whilst parsing JNet style secondary structure prediction.");\r
548         jalview.bin.Cache.log.debug("Exception: ",ex);\r
549       }\r
550     }\r
551   }\r
552 }\r