JAL-3690 recoded AWSThread to use javax.swing.Timer (see https://github.com/BobHanson...
[jalview.git] / src / jalview / ws / AWSThread.java
index 1fa4663..5748414 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
@@ -28,10 +28,22 @@ import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.WebserviceInfo;
+import jalview.util.MessageManager;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
 
-public abstract class AWSThread extends Thread
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.lang.String.format;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.Timer;
+
+public abstract class AWSThread
 {
+  
+  private javax.swing.Timer timer;
 
   /**
    * view that this job was associated with
@@ -56,17 +68,19 @@ public abstract class AWSThread extends Thread
   /**
    * dataset sequence relationships to be propagated onto new results
    */
-  protected AlignedCodonFrame[] codonframe = null;
+  protected List<AlignedCodonFrame> codonframe = null;
 
   /**
    * are there jobs still running in this thread.
+   *
+   * fixme: initialize with an empty array?
    */
   protected boolean jobComplete = false;
 
   /**
    * one or more jobs being managed by this thread.
    */
-  protected AWsJob jobs[] = null;
+  protected AWsJob[] jobs = null;
 
   /**
    * full name of service
@@ -86,112 +100,100 @@ public abstract class AWSThread extends Thread
    */
   protected String WsUrl = null;
 
-  /**
-   * generic web service job/subjob poll loop
+  /*
+   * The AlignFrame from which the service was requested.
    */
-  public void run()
+  private AlignFrame alignFrame;
+
+  public void start()
   {
-    JobStateSummary jstate = null;
     if (jobs == null)
     {
       jobComplete = true;
+      Cache.log.debug(
+          "WebServiceJob poll loop finished with no jobs created.");
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+      wsInfo.appendProgressText(
+          MessageManager.getString("info.no_jobs_ran"));
+      wsInfo.setFinishedNoResults();
+      return;
     }
-    while (!jobComplete)
+    timer = new Timer(5000, new ActionListener()
     {
-      jstate = new JobStateSummary();
-      for (int j = 0; j < jobs.length; j++)
+      
+      @Override
+      public void actionPerformed(ActionEvent e)
       {
-
-        if (!jobs[j].submitted && jobs[j].hasValidInput())
+        JobStateSummary jstate = new JobStateSummary();
+        for (final AWsJob job : jobs)
         {
-          StartJob(jobs[j]);
-        }
-
-        if (jobs[j].submitted && !jobs[j].subjobComplete)
-        {
-          try
+          if (!job.submitted && job.hasValidInput())
           {
-            pollJob(jobs[j]);
-            if (!jobs[j].hasResponse())
-            {
-              throw (new Exception(
-                      "Timed out when communicating with server\nTry again later.\n"));
-            }
-            jalview.bin.Cache.log.debug("Job " + j + " Result state "
-                    + jobs[j].getState() + "(ServerError="
-                    + jobs[j].isServerError() + ")");
-          } catch (Exception ex)
+            StartJob(job);
+          }
+          Cache.log.debug(format(
+                  "Job %s is %ssubmitted", job, job.submitted ? "" : "not "));
+          if (job.submitted && !job.subjobComplete)
           {
-            // Deal with Transaction exceptions
-            wsInfo.appendProgressText(jobs[j].jobnum, "\n" + WebServiceName
-                    + " Server exception!\n" + ex.getMessage());
-            // always output the exception's stack trace to the log
-            Cache.log.warn(WebServiceName + " job(" + jobs[j].jobnum
-                    + ") Server exception.");
-            // todo: could limit trace to cause if this is a SOAPFaultException.
-            ex.printStackTrace();
-
-            if (jobs[j].allowedServerExceptions > 0)
+            Cache.log.debug(format(
+                    "Polling Job %s Result state was:%s(ServerError=%b)",
+                    job, job.getState(), job.isServerError()));
+            try
             {
-              jobs[j].allowedServerExceptions--;
-              Cache.log.debug("Sleeping after a server exception.");
-              try
+              pollJob(job);
+              if (!job.hasResponse())
+                throw new Exception("Timed out when communicating with server. Try again later.");
+              else
+                Cache.log.debug(format("Job %s Result state:%s(ServerError=%b)",
+                        job, job.getState(), job.isServerError()));
+            } catch (Exception exc)
+            {
+              // Deal with Transaction exceptions
+              wsInfo.appendProgressText(job.jobnum, MessageManager
+                      .formatMessage("info.server_exception", WebServiceName,
+                          exc.getMessage()));
+              // always output the exception's stack trace to the log
+              Cache.log.warn(format("%s job(%s) Server exception.",
+                      WebServiceName, job.jobnum));
+              exc.printStackTrace();
+              
+              if (job.allowedServerExceptions > 0)
               {
-                Thread.sleep(5000);
-              } catch (InterruptedException ex1)
+                job.allowedServerExceptions--;
+              }
+              else
               {
+                Cache.log.warn(format("Dropping job %s %s", job, job.jobId));
+                job.subjobComplete = true;
+                wsInfo.setStatus(job.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
               }
-            }
-            else
+            } catch (OutOfMemoryError oomerror)
             {
-              Cache.log.warn("Dropping job " + j + " " + jobs[j].jobId);
-              jobs[j].subjobComplete = true;
-              wsInfo.setStatus(jobs[j].jobnum,
-                      WebserviceInfo.STATE_STOPPED_SERVERERROR);
+              jobComplete = true;
+              job.subjobComplete = true;
+              job.clearResponse();
+              wsInfo.setStatus(job.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
+              Cache.log.error(format("Out of memory when retrieving Job %s id:%s/%s",
+                      job, WsUrl, job.jobId), oomerror);
+              new jalview.gui.OOMWarning("retrieving result for " + WebServiceName, oomerror);
+              System.gc();
             }
-          } catch (OutOfMemoryError er)
-          {
-            jobComplete = true;
-            jobs[j].subjobComplete = true;
-            jobs[j].clearResponse(); // may contain out of date result data
-            wsInfo.setStatus(jobs[j].jobnum,
-                    WebserviceInfo.STATE_STOPPED_ERROR);
-            Cache.log.error("Out of memory when retrieving Job " + j
-                    + " id:" + WsUrl + "/" + jobs[j].jobId, er);
-            new jalview.gui.OOMWarning("retrieving result for "
-                    + WebServiceName, er);
-            System.gc();
           }
+          jstate.updateJobPanelState(wsInfo, OutputHeader, job);
         }
-        jstate.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
-      }
-      // Decide on overall state based on collected jobs[] states
-      updateGlobalStatus(jstate);
-      if (!jobComplete)
-      {
-        try
-        {
-          Thread.sleep(5000);
-        } catch (InterruptedException e)
+        // Decide on overall state based on collected jobs[] states
+        updateGlobalStatus(jstate);
+        if (jobComplete)
         {
-          Cache.log
-                  .debug("Interrupted sleep waiting for next job poll.", e);
+          timer.stop();
+          // jobs should never be null at this point
+          parseResult(); // tidy up and make results available to user
+          
         }
-        // System.out.println("I'm alive "+alTitle);
       }
-    }
-    if (jobComplete && jobs != null)
-    {
-      parseResult(); // tidy up and make results available to user
-    }
-    else
-    {
-      Cache.log
-              .debug("WebServiceJob poll loop finished with no jobs created.");
-      wsInfo.setStatus(wsInfo.STATE_STOPPED_ERROR);
-      wsInfo.appendProgressText("No jobs ran.");
-      wsInfo.setFinishedNoResults();
-    }
+    });
+    timer.setInitialDelay(0);
+    timer.start();
   }
 
   protected void updateGlobalStatus(JobStateSummary jstate)
@@ -221,40 +223,10 @@ public abstract class AWSThread extends Thread
       }
     }
   }
-
-  public AWSThread()
-  {
-    super();
-  }
-
-  public AWSThread(Runnable target)
-  {
-    super(target);
-  }
-
-  public AWSThread(String name)
+  
+  public void interrupt()
   {
-    super(name);
-  }
-
-  public AWSThread(ThreadGroup group, Runnable target)
-  {
-    super(group, target);
-  }
-
-  public AWSThread(ThreadGroup group, String name)
-  {
-    super(group, name);
-  }
-
-  public AWSThread(Runnable target, String name)
-  {
-    super(target, name);
-  }
-
-  public AWSThread(ThreadGroup group, Runnable target, String name)
-  {
-    super(group, target, name);
+    timer.stop();
   }
 
   /**
@@ -294,13 +266,12 @@ public abstract class AWSThread extends Thread
       SequenceI[] alignment = al.getSequencesArray();
       for (int sq = 0; sq < alignment.length; sq++)
       {
-        for (int i = 0; i < codonframe.length; i++)
+        for (AlignedCodonFrame acf : codonframe)
         {
-          if (codonframe[i] != null
-                  && codonframe[i].involvesSequence(alignment[sq]))
+          final SequenceI seq = alignment[sq];
+          if (acf != null && acf.involvesSequence(seq))
           {
-            al.addCodonFrame(codonframe[i]);
-            codonframe[i] = null;
+            al.addCodonFrame(acf);
             break;
           }
         }
@@ -308,12 +279,6 @@ public abstract class AWSThread extends Thread
     }
   }
 
-  public AWSThread(ThreadGroup group, Runnable target, String name,
-          long stackSize)
-  {
-    super(group, target, name, stackSize);
-  }
-
   /**
    * 
    * @return gap character to use for any alignment generation
@@ -327,7 +292,7 @@ public abstract class AWSThread extends Thread
    * 
    * @param alignFrame
    *          reference for copying mappings across
-   * @param wsInfo
+   * @param wsinfo
    *          gui attachment point
    * @param input
    *          input data for the calculation
@@ -359,7 +324,7 @@ public abstract class AWSThread extends Thread
           AlignmentView alview, String wsurl2)
   {
     super();
-    // this.alignFrame = alframe;
+    this.alignFrame = alframe;
     currentView = alframe.getCurrentView().getAlignment();
     featureSettings = alframe.getFeatureRenderer().getSettings();
     defGapChar = alframe.getViewport().getGapCharacter();
@@ -368,13 +333,18 @@ public abstract class AWSThread extends Thread
     WsUrl = wsurl2;
     if (alframe != null)
     {
-      AlignedCodonFrame[] cf = alframe.getViewport().getAlignment()
+      List<AlignedCodonFrame> cf = alframe.getViewport().getAlignment()
               .getCodonFrames();
       if (cf != null)
       {
-        codonframe = new AlignedCodonFrame[cf.length];
-        System.arraycopy(cf, 0, codonframe, 0, cf.length);
+        codonframe = new ArrayList<>();
+        codonframe.addAll(cf);
       }
     }
   }
+
+  protected AlignFrame getRequestingAlignFrame()
+  {
+    return this.alignFrame;
+  }
 }