2ec8e1e8999728b726291fc586ccadbd3a7d0f37
[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.bin.*;\r
28 import jalview.datamodel.*;\r
29 import jalview.datamodel.Alignment;\r
30 import jalview.gui.*;\r
31 import jalview.io.*;\r
32 import jalview.ws.WSThread.*;\r
33 import vamsas.objects.simple.*;\r
34 import jalview.util.Comparison;\r
35 \r
36 public class JPredClient\r
37     extends WSClient\r
38 {\r
39   public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI seq)\r
40   {\r
41     wsInfo = setWebService(sh);\r
42     startJPredClient(title, seq);\r
43   }\r
44 \r
45   public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI[] msa)\r
46   {\r
47     wsInfo = setWebService(sh);\r
48     startJPredClient(title, msa);\r
49   }\r
50 \r
51   public JPredClient(String title, SequenceI[] msf)\r
52   {\r
53     startJPredClient(title, msf);\r
54   }\r
55 \r
56   public JPredClient(String title, SequenceI seq)\r
57   {\r
58     startJPredClient(title, seq);\r
59   }\r
60 \r
61   private void startJPredClient(String title, SequenceI[] msf)\r
62   {\r
63     if (wsInfo == null)\r
64     {\r
65       wsInfo = setWebService();\r
66     }\r
67 \r
68     SequenceI seq = msf[0];\r
69 \r
70     String altitle = "JNet prediction on " + seq.getName() +\r
71         " using alignment from " + title;\r
72 \r
73     wsInfo.setProgressText("Job details for MSA based prediction (" +\r
74                            title + ") on sequence :\n>" + seq.getName() + "\n" +\r
75                            AlignSeq.extractGaps("-. ", seq.getSequence()) +\r
76                            "\n");\r
77     SequenceI aln[] = new SequenceI[msf.length];\r
78     for (int i = 0, j = msf.length; i < j; i++)\r
79     {\r
80       aln[i] = new jalview.datamodel.Sequence(msf[i]);\r
81     }\r
82 \r
83     Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true);\r
84 \r
85     Jpred server = locateWebService();\r
86     if (server==null)\r
87     {\r
88       return;\r
89     }\r
90 \r
91     JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, aln);\r
92     wsInfo.setthisService(jthread);\r
93     jthread.start();\r
94   }\r
95 \r
96   public void startJPredClient(String title, SequenceI seq)\r
97   {\r
98     if (wsInfo == null)\r
99     {\r
100       wsInfo = setWebService();\r
101     }\r
102     wsInfo.setProgressText("Job details for prediction on sequence :\n>" +\r
103                            seq.getName() + "\n" +\r
104                            AlignSeq.extractGaps("-. ", seq.getSequence()) +\r
105                            "\n");\r
106     String altitle = "JNet prediction for sequence " + seq.getName() + " from " +\r
107         title;\r
108 \r
109     Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash(seq);\r
110 \r
111     Jpred server = locateWebService();\r
112     if (server==null)\r
113     {\r
114       return;\r
115     }\r
116 \r
117     JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, seq);\r
118     wsInfo.setthisService(jthread);\r
119     jthread.start();\r
120   }\r
121 \r
122   private WebserviceInfo setWebService()\r
123   {\r
124     WebServiceName = "JNetWS";\r
125     WebServiceJobTitle = "JNet secondary structure prediction";\r
126     WebServiceReference =\r
127         "\"Cuff J. A and Barton G.J (2000) Application of " +\r
128         "multiple sequence alignment profiles to improve protein secondary structure prediction, " +\r
129         "Proteins 40:502-511\".";\r
130     WsURL = "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred";\r
131 \r
132     WebserviceInfo wsInfo = new WebserviceInfo(WebServiceJobTitle,\r
133                                                WebServiceReference);\r
134 \r
135     return wsInfo;\r
136   }\r
137 \r
138   private ext.vamsas.Jpred locateWebService()\r
139   {\r
140     ext.vamsas.JpredServiceLocator loc = new JpredServiceLocator(); // Default\r
141     ext.vamsas.Jpred server=null;\r
142     try\r
143     {\r
144       server = loc.getjpred(new java.net.URL(WsURL)); // JBPNote will be set from properties\r
145       ( (JpredSoapBindingStub)server).setTimeout(60000); // one minute stub\r
146       //((JpredSoapBindingStub)this.server)._setProperty(org.apache.axis.encoding.C, Boolean.TRUE);\r
147 \r
148     }\r
149     catch (Exception ex)\r
150     {\r
151       JOptionPane.showMessageDialog(Desktop.desktop,\r
152                                     "The Secondary Structure Prediction Service named " +\r
153                                     WebServiceName + " at " + WsURL +\r
154                                     " couldn't be located.",\r
155                                     "Internal Jalview Error",\r
156                                     JOptionPane.WARNING_MESSAGE);\r
157       wsInfo.setProgressText("Serious! " + WebServiceName +\r
158                              " Service location failed\nfor URL :" + WsURL +\r
159                              "\n" +\r
160                              ex.getMessage());\r
161       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
162 \r
163     }\r
164 \r
165     return server;\r
166   }\r
167 \r
168   class JPredThread\r
169       extends WSThread\r
170       implements WSClientI\r
171   {\r
172     class JPredJob\r
173         extends WSThread.WSJob\r
174     {\r
175 \r
176       vamsas.objects.simple.Sequence sequence;\r
177       vamsas.objects.simple.Msfalignment msa;\r
178       java.util.Hashtable SequenceInfo = null;\r
179       /**\r
180        *\r
181        * @return true if getResultSet will return a valid alignment and prediction result.\r
182        */\r
183       public boolean hasResults()\r
184       {\r
185         if (subjobComplete && result != null && result.isFinished()\r
186             && ( (JpredResult) result).getPredfile() != null &&\r
187             ( (JpredResult) result).getAligfile() != null)\r
188         {\r
189           return true;\r
190         }\r
191         return false;\r
192       }\r
193 \r
194       boolean hasValidInput()\r
195       {\r
196         if (sequence != null)\r
197         {\r
198           return true;\r
199         }\r
200         return false;\r
201       }\r
202 \r
203       public Alignment getResultSet()\r
204           throws Exception\r
205       {\r
206         if (result == null || !result.isFinished())\r
207         {\r
208           return null;\r
209         }\r
210         Alignment al = null;\r
211         int FirstSeq = -1; // the position of the query sequence in Alignment al\r
212         boolean noMsa = true; // set if no MSA has been returned by JPred\r
213 \r
214         JpredResult result = (JpredResult)this.result;\r
215 \r
216         jalview.bin.Cache.log.debug("Parsing output from JNet job.");\r
217         // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File");\r
218         jalview.io.JPredFile prediction = new jalview.io.JPredFile(result.\r
219             getPredfile(),\r
220             "Paste");\r
221         SequenceI[] preds = prediction.getSeqsAsArray();\r
222         jalview.bin.Cache.log.debug("Got prediction profile.");\r
223 \r
224         if ( (this.msa != null) && (result.getAligfile() != null))\r
225         {\r
226           jalview.bin.Cache.log.debug("Getting associated alignment.");\r
227           // we ignore the returned alignment if we only predicted on a single sequence\r
228           String format = new jalview.io.IdentifyFile().Identify(result.\r
229               getAligfile(),\r
230               "Paste");\r
231 \r
232           if (jalview.io.FormatAdapter.isValidFormat(format))\r
233           {\r
234             al = new Alignment(new FormatAdapter().readFile(result.getAligfile(),\r
235                 "Paste", format));\r
236             SequenceI sqs[] = new SequenceI[al.getHeight()];\r
237             for (int i = 0, j = al.getHeight(); i < j; i++)\r
238             {\r
239               sqs[i] = al.getSequenceAt(i);\r
240             }\r
241             if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable)\r
242                 SequenceInfo, sqs))\r
243             {\r
244               throw (new Exception(\r
245                   "Couldn't recover sequence properties for alignment."));\r
246             }\r
247 \r
248             noMsa = false;\r
249             FirstSeq = 0;\r
250           }\r
251           else\r
252           {\r
253             throw (new Exception(\r
254                 "Unknown format "+format+" for file : \n" +\r
255                 result.getAligfile()));\r
256           }\r
257         }\r
258         else\r
259         {\r
260           al = new Alignment(preds);\r
261           FirstSeq = prediction.getQuerySeqPosition();\r
262           if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(\r
263               al.getSequenceAt(FirstSeq), SequenceInfo))\r
264           {\r
265             throw (new Exception(\r
266                 "Couldn't recover sequence properties for JNet Query sequence!"));\r
267           }\r
268         }\r
269 \r
270         al.setDataset(null);\r
271 \r
272         jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq,\r
273             noMsa);\r
274         return al; // , FirstSeq, noMsa};\r
275       }\r
276       public JPredJob(Hashtable SequenceInfo, SequenceI seq)\r
277       {\r
278         super();\r
279         String sq = AlignSeq.extractGaps(Comparison.GapChars, seq.getSequence());\r
280         if (sq.length() >= 20)\r
281         {\r
282           this.SequenceInfo = SequenceInfo;\r
283           sequence = new vamsas.objects.simple.Sequence();\r
284           sequence.setId(seq.getName());\r
285           sequence.setSeq(sq);\r
286         }\r
287       }\r
288 \r
289       public JPredJob(Hashtable SequenceInfo, SequenceI[] msf)\r
290       {\r
291         this(SequenceInfo, msf[0]);\r
292         if (sequence != null)\r
293         {\r
294           if (msf.length > 1)\r
295           {\r
296             msa = new vamsas.objects.simple.Msfalignment();\r
297             jalview.io.PileUpfile pileup = new jalview.io.PileUpfile();\r
298             msa.setMsf(pileup.print(msf));\r
299           }\r
300         }\r
301       }\r
302     }\r
303     ext.vamsas.Jpred server;\r
304     String altitle = "";\r
305     JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server) {\r
306       this.altitle = altitle;\r
307       this.server = server;\r
308       this.wsInfo = wsinfo;\r
309     }\r
310 \r
311 //    String OutputHeader;\r
312 //    vamsas.objects.simple.JpredResult result;\r
313 \r
314     JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo,SequenceI seq)\r
315     {\r
316       this(wsinfo, altitle, server);\r
317       JPredJob job = new JPredJob(SequenceInfo, seq);\r
318       if (job.hasValidInput())\r
319       {\r
320         OutputHeader = wsInfo.getProgressText();\r
321         jobs = new WSJob[]\r
322             {\r
323             job};\r
324         job.jobnum = 0;\r
325       }\r
326     }\r
327 \r
328     JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo, SequenceI[] msf)\r
329     {\r
330       this(wsinfo, altitle, server);\r
331       JPredJob job = new JPredJob(SequenceInfo, msf);\r
332       if (job.hasValidInput())\r
333       {\r
334         jobs = new WSJob[]\r
335             {\r
336             job};\r
337         OutputHeader = wsInfo.getProgressText();\r
338         job.jobnum = 0;\r
339       }\r
340     }\r
341 \r
342     /*\r
343         public void run()\r
344         {\r
345           StartJob();\r
346 \r
347           while (!jobComplete && (allowedServerExceptions > 0))\r
348           {\r
349             try\r
350             {\r
351               if ( (result = server.getresult(jobId)) == null)\r
352               {\r
353                 throw (new Exception(\r
354      "Timed out when communicating with server\nTry again later.\n"));\r
355               }\r
356               if (result.getState()==0)\r
357                 jalview.bin.Cache.log.debug("Finished "+jobId);\r
358               if (result.isRunning())\r
359               {\r
360                 wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);\r
361               }\r
362               if (result.isQueued())\r
363               {\r
364                 wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);\r
365               }\r
366 \r
367               wsInfo.setProgressText(OutputHeader + "\n" +\r
368                                      result.getStatus());\r
369 \r
370               if (result.isFinished())\r
371               {\r
372 \r
373                 parseResult();\r
374                 jobComplete = true;\r
375                 jobsRunning--;\r
376               } else {\r
377                 // catch exceptions\r
378                 if (! (result.isJobFailed() || result.isServerError()))\r
379                 {\r
380                   try\r
381                   {\r
382                     Thread.sleep(5000);\r
383                   }\r
384                   catch (InterruptedException ex1)\r
385                   {\r
386                   }\r
387 \r
388                   //  System.out.println("I'm alive "+seqid+" "+jobid);\r
389                 }\r
390                 else\r
391                 {\r
392                   wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
393                   jobsRunning--;\r
394                   jobComplete = true;\r
395                 }\r
396               }\r
397             }\r
398             catch (Exception ex)\r
399             {\r
400               allowedServerExceptions--;\r
401 \r
402               wsInfo.appendProgressText("\nJPredWS Server exception!\n" +\r
403                                         ex.getMessage());\r
404 \r
405               try\r
406               {\r
407                 if (allowedServerExceptions > 0)\r
408                 {\r
409                   Thread.sleep(5000);\r
410                 }\r
411               }\r
412               catch (InterruptedException ex1)\r
413               {\r
414               }\r
415             }\r
416             catch (OutOfMemoryError er)\r
417             {\r
418               jobComplete = true;\r
419               wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
420               JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
421      "Out of memory handling result!!"\r
422                                                     +\r
423      "\nSee help files for increasing Java Virtual Machine memory."\r
424                                                     , "Out of memory",\r
425      JOptionPane.WARNING_MESSAGE);\r
426               System.out.println("JPredClient: "+er);\r
427               System.gc();\r
428             }\r
429           }\r
430           if (result!=null)\r
431             if (! (result.isJobFailed() || result.isServerError()))\r
432             {\r
433               wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
434             }\r
435             else\r
436             {\r
437               wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
438             }\r
439         }\r
440      */\r
441     void StartJob(WSJob j)\r
442     {\r
443       if (! (j instanceof JPredJob))\r
444       {\r
445         throw new Error("Implementation error - StartJob(JpredJob) called on " +\r
446                         j.getClass());\r
447       }\r
448       try\r
449       {\r
450         JPredJob job = (JPredJob) j;\r
451         if (job.msa != null)\r
452         {\r
453           job.jobId = server.predictOnMsa(job.msa);\r
454         }\r
455         else\r
456           if (job.sequence!=null)\r
457           {\r
458             job.jobId = server.predict(job.sequence);\r
459           }\r
460 \r
461         if (job.jobId != null)\r
462         {\r
463           if (job.jobId.startsWith("Broken"))\r
464           {\r
465             job.result = (vamsas.objects.simple.Result)new JpredResult();\r
466             job.result.setInvalid(true);\r
467             job.result.setStatus("Submission " + job.jobId);\r
468           }\r
469           else\r
470           {\r
471             job.submitted = true;\r
472             job.subjobComplete = false;\r
473             Cache.log.info(WsURL + " Job Id '" + job.jobId + "'");\r
474           }\r
475         }\r
476         else\r
477         {\r
478           throw new Exception("Server timed out - try again later\n");\r
479         }\r
480       }\r
481       catch (Exception e)\r
482       {\r
483         if (e.getMessage().indexOf("Exception") > -1)\r
484         {\r
485           wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
486           wsInfo.setProgressText(j.jobnum,\r
487                                  "Failed to submit the prediction. (Just close the window)\n"\r
488                                  +\r
489                                  "It is most likely that there is a problem with the server.\n");\r
490           System.err.println(\r
491               "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" +\r
492               e.getMessage() + "\n");\r
493 \r
494           jalview.bin.Cache.log.warn("Server Exception", e);\r
495         }\r
496         else\r
497         {\r
498           wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);\r
499           // JBPNote - this could be a popup informing the user of the problem.\r
500           wsInfo.appendProgressText(j.jobnum,\r
501                                     "Failed to submit the prediction:\n"\r
502                                     + e.getMessage() +\r
503                                     wsInfo.getProgressText());\r
504 \r
505           jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e);\r
506 \r
507         }\r
508         j.allowedServerExceptions = -1;\r
509         j.subjobComplete = true;\r
510       }\r
511     }\r
512 \r
513     /*  private void addFloatAnnotations(Alignment al, int[] gapmap,\r
514                                        Vector values, String Symname,\r
515                                        String Visname, float min,\r
516                                        float max, int winLength)\r
517       {\r
518         Annotation[] annotations = new Annotation[al.getWidth()];\r
519 \r
520         for (int j = 0; j < values.size(); j++)\r
521         {\r
522           float value = Float.parseFloat(values.get(j).toString());\r
523           annotations[gapmap[j]] = new Annotation("", value + "", ' ',\r
524                                                   value);\r
525         }\r
526 \r
527         al.addAnnotation(new AlignmentAnnotation(Symname, Visname,\r
528      annotations, min, max, winLength));\r
529       }*/\r
530 \r
531     void parseResult()\r
532     {\r
533       int results = 0; // number of result sets received\r
534       JobStateSummary finalState = new JobStateSummary();\r
535       try\r
536       {\r
537         for (int j = 0; j < jobs.length; j++)\r
538         {\r
539           finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);\r
540           if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())\r
541           {\r
542             results++;\r
543           }\r
544         }\r
545       }\r
546       catch (Exception ex)\r
547       {\r
548 \r
549         Cache.log.error("Unexpected exception when processing results for " +\r
550                         altitle, ex);\r
551         wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
552       }\r
553       if (results > 0)\r
554       {\r
555         wsInfo.showResultsNewFrame\r
556             .addActionListener(new java.awt.event.ActionListener()\r
557         {\r
558           public void actionPerformed(\r
559               java.awt.event.ActionEvent evt)\r
560           {\r
561             displayResults(true);\r
562           }\r
563         });\r
564         wsInfo.mergeResults\r
565             .addActionListener(new java.awt.event.ActionListener()\r
566         {\r
567           public void actionPerformed(\r
568               java.awt.event.ActionEvent evt)\r
569           {\r
570             displayResults(false);\r
571           }\r
572         });\r
573         wsInfo.setResultsReady();\r
574       }\r
575       else\r
576       {\r
577         wsInfo.setFinishedNoResults();\r
578       }\r
579     }\r
580 \r
581     void displayResults(boolean newWindow)\r
582     {\r
583       if (jobs != null)\r
584       {\r
585         Alignment res = null;\r
586         for (int jn = 0; jn < jobs.length; jn++)\r
587         {\r
588           Alignment jobres = null;\r
589           JPredJob j = (JPredJob) jobs[jn];\r
590 \r
591           if (j.hasResults())\r
592           {\r
593             try\r
594             {\r
595               jalview.bin.Cache.log.debug("Parsing output of job " + jn);\r
596               jobres = j.getResultSet();\r
597               jalview.bin.Cache.log.debug("Finished parsing output.");\r
598               if (jobs.length==1)\r
599                 res = jobres;\r
600               else {\r
601                   // do merge with other job results\r
602               }\r
603             }\r
604             catch (Exception e)\r
605             {\r
606               jalview.bin.Cache.log.error(\r
607                   "JNet Client: JPred Annotation Parse Error",\r
608                   e);\r
609               wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);\r
610               wsInfo.appendProgressText(j.jobnum,\r
611                                         OutputHeader + "\n" +\r
612                                         j.result.getStatus() +\r
613                                         "\nInvalid JNet job result data!\n" +\r
614                                         e.getMessage());\r
615               j.result.setBroken(true);\r
616             }\r
617           }\r
618         }\r
619 \r
620         if (res != null)\r
621         {\r
622           if (newWindow)\r
623           {\r
624             AlignFrame af = new AlignFrame(res);\r
625             Desktop.addInternalFrame(af, altitle,\r
626                                      AlignFrame.NEW_WINDOW_WIDTH,\r
627                                      AlignFrame.NEW_WINDOW_HEIGHT);\r
628           }\r
629           else\r
630           {\r
631             Cache.log.info("Append results onto existing alignment.");\r
632           }\r
633         }\r
634       }\r
635     }\r
636 \r
637     void pollJob(WSJob job)\r
638         throws Exception\r
639     {\r
640       job.result = server.getresult(job.jobId);\r
641     }\r
642     public boolean isCancellable()\r
643     {\r
644       return false;\r
645     }\r
646 \r
647     public void cancelJob()\r
648     {\r
649       throw new Error("Implementation error!");\r
650     }\r
651 \r
652   }\r
653 }\r
654 \r