Clover icon

Coverage Report

  1. Project Clover database Thu Nov 28 2024 18:06:40 GMT
  2. Package jalview.ws.rest

File RestJob.java

 

Coverage histogram

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

Code metrics

46
88
26
1
492
297
53
0.6
3.38
26
2.04

Classes

Class Line # Actions
RestJob 40 88 53
0.4545%
 

Contributing tests

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