Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.ws.rest

File RestJob.java

 

Coverage histogram

../../../img/srcFileCovDistChart5.png
43% of files have more coverage

Code metrics

46
88
26
1
493
298
53
0.6
3.38
26
2.04

Classes

Class Line # Actions
RestJob 41 88 53
0.4545%
 

Contributing tests

This file is covered by 3 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.ws.rest;
22   
23    import jalview.analysis.SeqsetUtils.SequenceInfo;
24    import jalview.datamodel.AlignmentAnnotation;
25    import jalview.datamodel.AlignmentI;
26    import jalview.datamodel.AlignmentOrder;
27    import jalview.datamodel.SequenceGroup;
28    import jalview.datamodel.SequenceI;
29    import jalview.io.packed.JalviewDataset;
30    import jalview.ws.AWsJob;
31    import jalview.ws.rest.params.Alignment;
32    import jalview.ws.rest.params.SeqGroupIndexVector;
33   
34    import java.util.ArrayList;
35    import java.util.Collection;
36    import java.util.Hashtable;
37    import java.util.Map;
38    import java.util.Set;
39    import java.util.Vector;
40   
 
41    public class RestJob extends AWsJob
42    {
43   
44    // TODO: input alignmentview and other data for this job
45    RestServiceDescription rsd;
46   
47    // boolean submitted;
48    boolean gotresponse;
49   
50    boolean error;
51   
52    boolean waiting;
53   
54    boolean gotresult;
55   
56    Map<String, SequenceInfo> squniq;
57   
58    /**
59    * dataset associated with this input data.
60    */
61    AlignmentI dsForIO;
62   
63    AlignmentOrder inputOrder;
64   
65    /**
66    * context of input data with respect to an AlignmentView's visible contigs.
67    */
68    int[] origviscontig;
69   
70    private AlignmentI contextAl = null;
71   
72    /**
73    * create a rest job using data bounded by the given start/end column.
74    *
75    * @param addJobPane
76    * @param restJobThread
77    * @param _input
78    * @param viscontigs
79    * visible contigs of an alignment view from which _input was derived
80    */
 
81  3 toggle public RestJob(int jobNum, RestJobThread restJobThread, AlignmentI _input,
82    int[] viscontigs)
83    {
84  3 rsd = restJobThread.restClient.service;
85  3 jobnum = jobNum;
86  3 if (viscontigs != null)
87    {
88  2 origviscontig = new int[viscontigs.length];
89  2 System.arraycopy(viscontigs, 0, origviscontig, 0, viscontigs.length);
90    }
91    // get sequences for the alignmentI
92    // get groups trimmed to alignment columns
93    // get any annotation trimmed to start/end columns, too.
94  3 squniq = jalview.analysis.SeqsetUtils
95    .uniquify(_input.getSequencesArray(), true);
96    // prepare input
97    // form alignment+groups+annotation,preprocess and then record references
98    // for formatters
99  3 ArrayList<InputType> alinp = new ArrayList<InputType>();
100  3 int paramsWithData = 0;
101    // TODO: JAL-715 - generalise the following validation logic for all
102    // parameter types
103    // we cheat for moment - since we know a-priori what data is available and
104    // what inputs we have implemented so far
105  3 for (Map.Entry<String, InputType> prm : rsd.inputParams.entrySet())
106    {
107  6 if (!prm.getValue().isConstant())
108    {
109  6 if (prm.getValue() instanceof Alignment)
110    {
111  3 alinp.add(prm.getValue());
112    }
113    else
114    {
115  3 if (prm.getValue() instanceof SeqGroupIndexVector
116    && _input.getGroups() != null
117    && _input.getGroups().size() >= -1 + prm.getValue().min)
118    {
119    // the test above is not rigorous but fixes JAL-1298, since
120    // submission will fail if the partition set doesn't contain at
121    // least one partition
122  3 alinp.add(prm.getValue());
123    }
124    else
125    {
126  0 statMessage = ("Not enough groups defined on the alignment - need at least "
127    + prm.getValue().min);
128    }
129    }
130    }
131    else
132    {
133  0 paramsWithData++;
134    }
135    }
136  3 if ((paramsWithData + alinp.size()) == rsd.inputParams.size())
137    {
138  3 inputOrder = new AlignmentOrder(_input);
139  ? if ((dsForIO = _input.getDataset()) == null)
140    {
141  2 _input.setDataset(null);
142    }
143  3 dsForIO = _input.getDataset();
144  3 if (contextAl == null)
145    {
146  3 contextAl = _input;
147    }
148  3 setAlignmentForInputs(alinp, _input);
149  3 validInput = true;
150    }
151    else
152    {
153    // not enough data, so we bail.
154  0 validInput = false;
155    }
156    }
157   
158    boolean validInput = false;
159   
 
160  0 toggle @Override
161    public boolean hasResults()
162    {
163  0 return gotresult && (parsedResults ? validJvresults : true);
164    }
165   
 
166  2 toggle @Override
167    public boolean hasValidInput()
168    {
169  2 return validInput;
170    }
171   
 
172  1 toggle @Override
173    public boolean isRunning()
174    {
175  1 return running; // TODO: can we check the response body for status messages
176    // ?
177    }
178   
 
179  1 toggle @Override
180    public boolean isQueued()
181    {
182  1 return waiting;
183    }
184   
 
185  1 toggle @Override
186    public boolean isFinished()
187    {
188  1 return resSet != null;
189    }
190   
 
191  1 toggle @Override
192    public boolean isFailed()
193    {
194    // TODO logic for error
195  1 return error;
196    }
197   
 
198  1 toggle @Override
199    public boolean isBroken()
200    {
201    // TODO logic for error
202  1 return error;
203    }
204   
 
205  1 toggle @Override
206    public boolean isServerError()
207    {
208    // TODO logic for error
209  1 return error;
210    }
211   
 
212  1 toggle @Override
213    public boolean hasStatus()
214    {
215  1 return statMessage != null;
216    }
217   
218    protected String statMessage = null;
219   
220    public HttpResultSet resSet;
221   
 
222  1 toggle @Override
223    public String getStatus()
224    {
225  1 return statMessage;
226    }
227   
 
228  0 toggle @Override
229    public boolean hasResponse()
230    {
231  0 return statMessage != null || resSet != null;
232    }
233   
 
234  0 toggle @Override
235    public void clearResponse()
236    {
237    // only clear the transient server response
238    // statMessage=null;
239    }
240   
241    /*
242    * (non-Javadoc)
243    *
244    * @see jalview.ws.AWsJob#getState()
245    */
 
246  0 toggle @Override
247    public String getState()
248    {
249    // TODO generate state string - prolly should have a default abstract method
250    // for this
251  0 return "Job is clueless";
252    }
253   
 
254  1 toggle public String getPostUrl()
255    {
256   
257    // TODO Auto-generated method stub
258  1 return rsd.postUrl;
259    }
260   
 
261  1 toggle public Set<Map.Entry<String, InputType>> getInputParams()
262    {
263  1 return rsd.inputParams.entrySet();
264    }
265   
266    // return the URL that should be polled for this job
 
267  0 toggle public String getPollUrl()
268    {
269  0 return rsd.getDecoratedResultUrl(jobId);
270    }
271   
272    /**
273    *
274    * @return the context for parsing results from service
275    */
 
276  0 toggle public JalviewDataset newJalviewDataset()
277    {
278  0 if (context == null)
279    {
280  0 context = new JalviewDataset(dsForIO, null, squniq, null);
281  0 if (contextAl != null)
282    {
283    // TODO devise way of merging new annotation onto (identical) existing
284    // annotation that was used as input
285    // delete all input annotation
286  0 if (contextAl.getAlignmentAnnotation() != null)
287    {
288  0 for (AlignmentAnnotation alan : contextAl
289    .getAlignmentAnnotation())
290    {
291  0 contextAl.deleteAnnotation(alan);
292    }
293    }
294    // TODO devise way of merging new groups onto (identical) existing
295    // groups when they were used as input to service
296    // delete all existing groups
297  0 if (contextAl.getGroups() != null)
298    {
299  0 contextAl.deleteAllGroups();
300    }
301  0 context.addAlignment(contextAl);
302    }
303   
304    }
305  0 return context;
306    }
307   
308    /**
309    * Extract list of sequence IDs for input parameter 'token' with given
310    * molecule type
311    *
312    * @param token
313    * @param type
314    * @return
315    */
 
316  0 toggle public SequenceI[] getSequencesForInput(String token,
317    InputType.molType type) throws NoValidInputDataException
318    {
319  0 Object sgdat = inputData.get(token);
320    // can we form an alignment from this data ?
321  0 if (sgdat == null)
322    {
323  0 throw new NoValidInputDataException(
324    "No Sequence vector data bound to input '" + token
325    + "' for service at " + rsd.postUrl);
326    }
327  0 if (sgdat instanceof AlignmentI)
328    {
329  0 return ((AlignmentI) sgdat).getSequencesArray();
330    }
331  0 if (sgdat instanceof SequenceGroup)
332    {
333  0 return ((SequenceGroup) sgdat).getSequencesAsArray(null);
334    }
335  0 if (sgdat instanceof Vector)
336    {
337  0 if (((Vector) sgdat).size() > 0
338    && ((Vector) sgdat).get(0) instanceof SequenceI)
339    {
340  0 SequenceI[] sq = new SequenceI[((Vector) sgdat).size()];
341  0 ((Vector) sgdat).copyInto(sq);
342  0 return sq;
343    }
344    }
345  0 throw new NoValidInputDataException(
346    "No Sequence vector data bound to input '" + token
347    + "' for service at " + rsd.postUrl);
348    }
349   
350    /**
351    * binding between input data (AlignmentI, SequenceGroup, NJTree) and input
352    * param names.
353    */
354    private Hashtable<String, Object> inputData = new Hashtable<String, Object>();
355   
356    /**
357    * is the job fully submitted to server and apparently in progress ?
358    */
359    public boolean running = false;
360   
361    /**
362    *
363    * @param itypes
364    * @param al
365    * - reference to object to be stored as input. Note - input data may
366    * be modifed by formatter
367    */
 
368  4 toggle public void setAlignmentForInputs(Collection<InputType> itypes,
369    AlignmentI al)
370    {
371  4 for (InputType itype : itypes)
372    {
373  8 if (!rsd.inputParams.values().contains(itype))
374    {
375  0 throw new IllegalArgumentException("InputType " + itype.getClass()
376    + " is not valid for service at " + rsd.postUrl);
377    }
378  8 if (itype instanceof AlignmentProcessor)
379    {
380  4 ((AlignmentProcessor) itype).prepareAlignment(al);
381    }
382    // stash a reference for recall when the alignment data is formatted
383  8 inputData.put(itype.token, al);
384    }
385   
386    }
387   
388    /**
389    *
390    * @param token
391    * @param type
392    * @return alignment object bound to the given token
393    * @throws NoValidInputDataException
394    */
 
395  4 toggle public AlignmentI getAlignmentForInput(String token,
396    InputType.molType type) throws NoValidInputDataException
397    {
398  4 Object al = inputData.get(token);
399    // can we form an alignment from this data ?
400  4 if (al == null || !(al instanceof AlignmentI))
401    {
402  0 throw new NoValidInputDataException(
403    "No alignment data bound to input '" + token
404    + "' for service at " + rsd.postUrl);
405    }
406  4 return (AlignmentI) al;
407    }
408   
409    /**
410    * test to see if the job has data of type cl that's needed for the job to run
411    *
412    * @param cl
413    * @return true or false
414    */
 
415  2 toggle public boolean hasDataOfType(Class cl)
416    {
417  2 if (AlignmentI.class.isAssignableFrom(cl))
418    {
419  2 return true;
420    }
421    // TODO: add more source data types
422   
423  0 return false;
424    }
425   
426    /**
427    * context used to parse results from service
428    */
429    JalviewDataset context = null;
430   
431    protected boolean parsedResults = false;
432   
433    protected boolean validJvresults = false;
434   
435    Object[] jvresultobj = null;
436   
437    /**
438    * process the results obtained from the server into jalview datamodel objects
439    * ready to be merged/added to the users' view. Use hasResults to test if
440    * results were added to context.
441    */
 
442  0 toggle public void parseResultSet() throws Exception, Error
443    {
444  0 if (!parsedResults)
445    {
446  0 parsedResults = true;
447  0 jvresultobj = resSet.parseResultSet();
448  0 validJvresults = true;
449    }
450    }
451   
452    /**
453    *
454    * @return true if job has an input alignment and it was annotated when
455    * results were parsed
456    */
 
457  0 toggle public boolean isInputContextModified()
458    {
459  0 return contextAl != null && validJvresults
460    && context.getAl().get(0).isModified();
461    }
462   
463    /**
464    *
465    * @return true if the ID/metadata for the input sequences were saved and
466    * sequence IDs renamed.
467    */
 
468  0 toggle public boolean isInputUniquified()
469    {
470    // TODO Auto-generated method stub
471  0 return false;
472    }
473   
474    /**
475    * Return map between ordering of alignment submitted as input, and ordering
476    * of alignment as provided by user
477    *
478    * @return int[sequence index in submitted data]==sequence index in input.
479    */
 
480  0 toggle public int[] getOrderMap()
481    {
482  0 SequenceI[] contseq = contextAl.getSequencesArray();
483  0 int map[] = new int[contseq.length];
484  0 for (int i = 0; i < contseq.length; i++)
485    {
486    // TODO: optimise for large N - build a lookup hash for IDs returning
487    // order, and then lookup each sequ's original order
488  0 map[i] = inputOrder.getOrder().indexOf(contseq[i]);
489    }
490  0 return map;
491    }
492   
493    }