Update annotation operation WIP
[jalview.git] / src / jalview / ws2 / operations / AnnotationOperation.java
1 package jalview.ws2.operations;
2
3 import java.io.IOException;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.concurrent.CancellationException;
8 import java.util.concurrent.CompletionStage;
9
10 import javax.swing.JMenu;
11 import javax.swing.JMenuItem;
12
13 import jalview.bin.Cache;
14 import jalview.datamodel.AlignmentAnnotation;
15 import jalview.gui.AlignFrame;
16 import jalview.gui.WsJobParameters;
17 import jalview.io.AnnotationFile;
18 import jalview.io.FeaturesFile;
19 import jalview.util.MathUtils;
20 import jalview.util.MessageManager;
21 import jalview.ws.params.ArgumentI;
22 import jalview.ws.params.WsParamSetI;
23 import jalview.ws2.MenuEntryProviderI;
24 import jalview.ws2.ResultSupplier;
25 import jalview.ws2.WSJob;
26 import jalview.ws2.WSJobStatus;
27 import jalview.ws2.WebServiceExecutor;
28 import jalview.ws2.WebServiceI;
29 import jalview.ws2.WebServiceWorkerI;
30 import jalview.ws2.utils.WSJobList;
31
32 import static java.lang.String.format;
33
34 /**
35  * 
36  * @author mmwarowny
37  *
38  */
39 public class AnnotationOperation implements Operation
40 {
41   final WebServiceI service;
42
43   final String typeName;
44
45   final ResultSupplier<List<AlignmentAnnotation>> annotationSupplier;
46
47   final ResultSupplier<FeaturesFile> featuresSupplier;
48
49   public AnnotationOperation(WebServiceI service,
50       ResultSupplier<List<AlignmentAnnotation>> annotSupplier,
51       ResultSupplier<FeaturesFile> featSupplier, String operationName)
52   {
53     this.service = service;
54     this.annotationSupplier = annotSupplier;
55     this.featuresSupplier = featSupplier;
56     this.typeName = operationName;
57   }
58
59   @Override
60   public String getName()
61   {
62     return service.getName();
63   }
64
65   @Override
66   public String getTypeName()
67   {
68     return typeName;
69   }
70
71   @Override
72   public String getHostName()
73   {
74     return service.getHostName();
75   }
76
77   @Override
78   public int getMinSequences()
79   {
80     return 0;
81   }
82
83   @Override
84   public int getMaxSequences()
85   {
86     return Integer.MAX_VALUE;
87   }
88
89   @Override
90   public boolean canSubmitGaps()
91   {
92     return false;
93   }
94
95   @Override
96   public boolean isProteinOperation()
97   {
98     return true;
99   }
100
101   @Override
102   public boolean isNucleotideOperation()
103   {
104     return true;
105   }
106
107   @Override
108   public boolean isInteractive()
109   {
110     return false;
111   }
112
113   @Override
114   public MenuEntryProviderI getMenuBuilder()
115   {
116     return this::buildMenu;
117   }
118
119   protected void buildMenu(JMenu parent, AlignFrame frame)
120   {
121     final var calcName = service.getName();
122     WebServiceExecutor wsExecutor = frame.getViewport().getWSExecutor();
123     {
124       var item = new JMenuItem(MessageManager.formatMessage(
125           "label.calcname_with_default_settings", calcName));
126       item.addActionListener((event) -> {
127         WebServiceWorkerI worker = new AnnotationWorker();
128         wsExecutor.submit(worker);
129       });
130       parent.add(item);
131     }
132     if (service.hasParameters())
133     {
134       var item = new JMenuItem(
135           MessageManager.getString("label.edit_settings_and_run"));
136       item.setToolTipText(MessageManager.getString(
137           "label.view_and_change_parameters_before_running_calculation"));
138       item.addActionListener((event) -> {
139         openEditParamsDialog(service, null, null)
140             .thenAcceptAsync((arguments) -> {
141               if (arguments != null)
142               {
143                 
144               }
145             });
146       });
147     }
148   }
149
150   private CompletionStage<List<ArgumentI>> openEditParamsDialog(
151       WebServiceI service, WsParamSetI preset, List<ArgumentI> arguments)
152   {
153     WsJobParameters jobParams;
154     if (preset == null && arguments != null && arguments.size() > 0)
155       jobParams = new WsJobParameters(service.getParamStore(), preset,
156           arguments);
157     else
158       jobParams = new WsJobParameters(service.getParamStore(), preset,
159           null);
160     if (preset != null)
161     {
162       jobParams.setName(MessageManager.getString(
163           "label.adjusting_parameters_for_calculation"));
164     }
165     var stage = jobParams.showRunDialog();
166     return stage.thenApply((startJob) -> {
167       if (startJob)
168       {
169         if (jobParams.getPreset() == null)
170           return jobParams.getJobParams();
171         else
172           return jobParams.getPreset().getArguments();
173       }
174       else
175       {
176         return null;
177       }
178     });
179   }
180
181   private class AnnotationWorker implements WebServiceWorkerI
182   {
183     private long uid = MathUtils.getUID();
184
185     private WSJobList jobs = new WSJobList();
186
187     private HashMap<Long, Integer> exceptionCount = new HashMap<>();
188
189     private static final int MAX_RETRY = 5;
190
191     @Override
192     public long getUID()
193     {
194       return uid;
195     }
196
197     @Override
198     public WebServiceI getWebService()
199     {
200       return service;
201     }
202
203     @Override
204     public List<WSJob> getJobs()
205     {
206       return Collections.unmodifiableList(jobs);
207     }
208
209     @Override
210     public void startJobs() throws IOException
211     {
212       
213     }
214
215     @Override
216     public boolean pollJobs() throws IOException
217     {
218       boolean done = true;
219       for (WSJob job : getJobs())
220       {
221         if (!job.getStatus().isDone() && !job.getStatus().isFailed())
222         {
223           Cache.log.debug(format("Polling job %s", job));
224           try
225           {
226             service.updateProgress(job);
227             exceptionCount.remove(job.getUid());
228           } catch (IOException e)
229           {
230             Cache.log.error(format("Polling job %s failed.", job), e);
231             int count = exceptionCount.getOrDefault(job.getUid(),
232                 MAX_RETRY);
233             if (--count <= 0)
234             {
235               job.setStatus(WSJobStatus.SERVER_ERROR);
236               Cache.log.warn(format(
237                   "Attempts limit exceeded. Droping job %s.", job));
238             }
239             exceptionCount.put(job.getUid(), count);
240           } catch (OutOfMemoryError e)
241           {
242             job.setStatus(WSJobStatus.BROKEN);
243             Cache.log.error(
244                 format("Out of memory when retrieving job %s", job), e);
245           }
246           Cache.log.debug(
247               format("Job %s status is %s", job, job.getStatus()));
248         }
249         done &= job.getStatus().isDone() || job.getStatus().isFailed();
250       }
251       return done;
252     }
253
254     @Override
255     public void done()
256     {
257       // TODO Auto-generated method stub
258
259     }
260
261   }
262 }