apparent bug in JpredFile parser where annotation was not being removed from alignmen...
[jalview.git] / src / jalview / ws / WSThread.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.ws;
20
21 import javax.swing.*;
22
23 import jalview.bin.*;
24 import jalview.datamodel.*;
25 import jalview.gui.*;
26
27 public abstract class WSThread
28     extends Thread
29 {
30   /**
31    * Generic properties for Web Service Client threads.
32    */
33   AlignFrame alignFrame = null;
34   WebserviceInfo wsInfo = null;
35   AlignmentView input = null;
36   boolean jobComplete = false;
37   abstract class WSJob
38   {
39     /**
40      * Generic properties for an individual job within a Web Service Client thread
41      */
42     int jobnum = 0; // WebServiceInfo pane for this job
43     String jobId; // ws job ticket
44     boolean cancelled = false;
45     int allowedServerExceptions = 3; // job dies if too many exceptions.
46     boolean submitted = false;
47     boolean subjobComplete = false;
48     /**
49      *
50      * @return true if job has completed and valid results are available
51      */
52     abstract boolean hasResults();
53
54     /**
55      *
56      * @return boolean true if job can be submitted.
57      */
58     abstract boolean hasValidInput();
59
60     vamsas.objects.simple.Result result;
61   }
62
63   class JobStateSummary
64   {
65     int running = 0;
66     int queuing = 0;
67     int finished = 0;
68     int error = 0;
69     int serror = 0;
70     int cancelled = 0;
71     int results = 0;
72     void updateJobPanelState(WebserviceInfo wsInfo, String OutputHeader,
73                              WSJob j)
74     {
75       if (j.result != null)
76       {
77         String progheader = "";
78         // Parse state of job[j]
79         if (j.result.isRunning())
80         {
81           running++;
82           wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_RUNNING);
83         }
84         else if (j.result.isQueued())
85         {
86           queuing++;
87           wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_QUEUING);
88         }
89         else if (j.result.isFinished())
90         {
91           finished++;
92           j.subjobComplete = true;
93           if (j.hasResults())
94           {
95             results++;
96           }
97           wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_OK);
98         }
99         else if (j.result.isFailed())
100         {
101           progheader += "Job failed.\n";
102           j.subjobComplete = true;
103           wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
104           error++;
105         }
106         else if (j.result.isServerError())
107         {
108           serror++;
109           j.subjobComplete = true;
110           wsInfo.setStatus(j.jobnum,
111                            WebserviceInfo.STATE_STOPPED_SERVERERROR);
112         }
113         else if (j.result.isBroken() || j.result.isFailed())
114         {
115           error++;
116           j.subjobComplete = true;
117           wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
118         }
119         // and pass on any sub-job messages to the user
120         wsInfo.setProgressText(j.jobnum, OutputHeader);
121         wsInfo.appendProgressText(j.jobnum, progheader);
122         if (j.result.getStatus() != null)
123         {
124           wsInfo.appendProgressText(j.jobnum, j.result.getStatus());
125         }
126       }
127       else
128       {
129         if (j.submitted && j.subjobComplete)
130         {
131           if (j.allowedServerExceptions == 0)
132           {
133             serror++;
134           }
135           else if (j.result == null)
136           {
137             error++;
138           }
139         }
140       }
141     }
142   }
143
144   WSJob jobs[] = null;
145   String WebServiceName = null;
146   String OutputHeader;
147   String WsUrl = null;
148   abstract void pollJob(WSJob job)
149       throws Exception;
150
151   public void run()
152   {
153     JobStateSummary jstate = null;
154     if (jobs == null)
155     {
156       jobComplete = true;
157     }
158     while (!jobComplete)
159     {
160       jstate = new JobStateSummary();
161       for (int j = 0; j < jobs.length; j++)
162       {
163
164         if (!jobs[j].submitted && jobs[j].hasValidInput())
165         {
166           StartJob(jobs[j]);
167         }
168
169         if (jobs[j].submitted && !jobs[j].subjobComplete)
170         {
171           try
172           {
173             pollJob(jobs[j]);
174             if (jobs[j].result == null)
175             {
176               throw (new Exception(
177                   "Timed out when communicating with server\nTry again later.\n"));
178             }
179             jalview.bin.Cache.log.debug("Job " + j + " Result state " +
180                                         jobs[j].result.getState()
181                                         + "(ServerError=" +
182                                         jobs[j].result.isServerError() + ")");
183           }
184           catch (Exception ex)
185           {
186             // Deal with Transaction exceptions
187             wsInfo.appendProgressText(jobs[j].jobnum, "\n" + WebServiceName
188                                       + " Server exception!\n" + ex.getMessage());
189             Cache.log.warn(WebServiceName + " job(" + jobs[j].jobnum
190                            + ") Server exception: " + ex.getMessage());
191
192             if (jobs[j].allowedServerExceptions > 0)
193             {
194               jobs[j].allowedServerExceptions--;
195               Cache.log.debug("Sleeping after a server exception.");
196               try
197               {
198                 Thread.sleep(5000);
199               }
200               catch (InterruptedException ex1)
201               {
202               }
203             }
204             else
205             {
206               Cache.log.warn("Dropping job " + j + " " + jobs[j].jobId);
207               jobs[j].subjobComplete = true;
208               wsInfo.setStatus(jobs[j].jobnum,
209                                WebserviceInfo.STATE_STOPPED_SERVERERROR);
210             }
211           }
212           catch (OutOfMemoryError er)
213           {
214             jobComplete = true;
215             jobs[j].subjobComplete = true;
216             jobs[j].result = null; // may contain out of date result object
217             wsInfo.setStatus(jobs[j].jobnum,
218                              WebserviceInfo.STATE_STOPPED_ERROR);
219             JOptionPane
220                 .showInternalMessageDialog(
221                     Desktop.desktop,
222                     "Out of memory handling result for job !!"
223                     +
224                     "\nSee help files for increasing Java Virtual Machine memory.",
225                     "Out of memory", JOptionPane.WARNING_MESSAGE);
226             Cache.log.error("Out of memory when retrieving Job " + j + " id:" +
227                             WsUrl + "/" + jobs[j].jobId, er);
228             System.gc();
229           }
230         }
231         jstate.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
232       }
233       // Decide on overall state based on collected jobs[] states
234       if (jstate.running > 0)
235       {
236         wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);
237       }
238       else if (jstate.queuing > 0)
239       {
240         wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);
241       }
242       else
243       {
244         jobComplete = true;
245         if (jstate.finished > 0)
246         {
247           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);
248         }
249         else if (jstate.error > 0)
250         {
251           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
252         }
253         else if (jstate.serror > 0)
254         {
255           wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
256         }
257       }
258       if (!jobComplete)
259       {
260         try
261         {
262           Thread.sleep(5000);
263         }
264         catch (InterruptedException e)
265         {
266           Cache.log.debug("Interrupted sleep waiting for next job poll.", e);
267         }
268         // System.out.println("I'm alive "+alTitle);
269       }
270     }
271     if (jobComplete && jobs != null)
272     {
273       parseResult(); // tidy up and make results available to user
274     }
275     else
276     {
277       Cache.log.debug("WebServiceJob poll loop finished with no jobs created.");
278     }
279   }
280
281   abstract void StartJob(WSJob job);
282
283   abstract void parseResult();
284 }