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