2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
3 * Copyright (C) 2014 The Jalview Authors
5 * This file is part of Jalview.
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
17 * The Jalview Authors are detailed in the 'AUTHORS' file.
19 package jalview.ws.rest;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Hashtable;
26 import java.util.Vector;
28 import jalview.datamodel.AlignmentAnnotation;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.AlignmentOrder;
31 import jalview.datamodel.SequenceGroup;
32 import jalview.datamodel.SequenceI;
33 import jalview.io.packed.JalviewDataset;
34 import jalview.ws.AWsJob;
35 import jalview.ws.rest.params.Alignment;
36 import jalview.ws.rest.params.SeqGroupIndexVector;
38 public class RestJob extends AWsJob
41 // TODO: input alignmentview and other data for this job
42 RestServiceDescription rsd;
56 * dataset associated with this input data.
60 AlignmentOrder inputOrder;
63 * context of input data with respect to an AlignmentView's visible contigs.
67 private AlignmentI contextAl = null;
70 * create a rest job using data bounded by the given start/end column.
73 * @param restJobThread
76 * visible contigs of an alignment view from which _input was derived
78 public RestJob(int jobNum, RestJobThread restJobThread,
79 AlignmentI _input, int[] viscontigs)
81 rsd = restJobThread.restClient.service;
83 if (viscontigs != null)
85 origviscontig = new int[viscontigs.length];
86 System.arraycopy(viscontigs, 0, origviscontig, 0, viscontigs.length);
88 // get sequences for the alignmentI
89 // get groups trimmed to alignment columns
90 // get any annotation trimmed to start/end columns, too.
91 squniq = jalview.analysis.SeqsetUtils.uniquify(_input.getSequencesArray(), true);
93 // form alignment+groups+annotation,preprocess and then record references
95 ArrayList<InputType> alinp = new ArrayList<InputType>();
96 int paramsWithData = 0;
97 // TODO: JAL-715 - generalise the following validation logic for all parameter types
98 // we cheat for moment - since we know a-priori what data is available and
99 // what inputs we have implemented so far
100 for (Map.Entry<String, InputType> prm : rsd.inputParams.entrySet())
102 if (!prm.getValue().isConstant())
104 if (prm.getValue() instanceof Alignment)
106 alinp.add(prm.getValue());
110 if (prm.getValue() instanceof SeqGroupIndexVector
111 && _input.getGroups() != null
112 && _input.getGroups().size() >= -1 + prm.getValue().min)
114 // the test above is not rigorous but fixes JAL-1298, since submission will fail if the partition set doesn't contain at least one partition
115 alinp.add(prm.getValue());
119 statMessage = ("Not enough groups defined on the alignment - need at least " + prm
129 if ((paramsWithData + alinp.size()) == rsd.inputParams.size())
131 inputOrder = new AlignmentOrder(_input);
132 if ((dsForIO = _input.getDataset()) == null)
134 _input.setDataset(null);
136 dsForIO = _input.getDataset();
137 if (contextAl == null)
141 setAlignmentForInputs(alinp, _input);
146 // not enough data, so we bail.
151 boolean validInput = false;
154 public boolean hasResults()
156 return gotresult && (parsedResults ? validJvresults : true);
160 public boolean hasValidInput()
166 public boolean isRunning()
168 return running; // TODO: can we check the response body for status messages
173 public boolean isQueued()
179 public boolean isFinished()
181 return resSet != null;
185 public boolean isFailed()
187 // TODO logic for error
192 public boolean isBroken()
194 // TODO logic for error
199 public boolean isServerError()
201 // TODO logic for error
206 public boolean hasStatus()
208 return statMessage != null;
211 protected String statMessage = null;
213 public HttpResultSet resSet;
216 public String getStatus()
222 public boolean hasResponse()
224 return statMessage != null || resSet != null;
228 public void clearResponse()
230 // only clear the transient server response
237 * @see jalview.ws.AWsJob#getState()
240 public String getState()
242 // TODO generate state string - prolly should have a default abstract method
244 return "Job is clueless";
247 public String getPostUrl()
250 // TODO Auto-generated method stub
254 public Set<Map.Entry<String, InputType>> getInputParams()
256 return rsd.inputParams.entrySet();
259 // return the URL that should be polled for this job
260 public String getPollUrl()
262 return rsd.getDecoratedResultUrl(jobId);
267 * @return the context for parsing results from service
269 public JalviewDataset newJalviewDataset()
273 context = new JalviewDataset(dsForIO, null, squniq, null);
274 if (contextAl != null)
276 // TODO devise way of merging new annotation onto (identical) existing
277 // annotation that was used as input
278 // delete all input annotation
279 if (contextAl.getAlignmentAnnotation() != null)
281 for (AlignmentAnnotation alan : contextAl
282 .getAlignmentAnnotation())
284 contextAl.deleteAnnotation(alan);
287 // TODO devise way of merging new groups onto (identical) existing
288 // groups when they were used as input to service
289 // delete all existing groups
290 if (contextAl.getGroups() != null)
292 contextAl.deleteAllGroups();
294 context.addAlignment(contextAl);
302 * Extract list of sequence IDs for input parameter 'token' with given
309 public SequenceI[] getSequencesForInput(String token,
310 InputType.molType type) throws NoValidInputDataException
312 Object sgdat = inputData.get(token);
313 // can we form an alignment from this data ?
316 throw new NoValidInputDataException(
317 "No Sequence vector data bound to input '" + token
318 + "' for service at " + rsd.postUrl);
320 if (sgdat instanceof AlignmentI)
322 return ((AlignmentI) sgdat).getSequencesArray();
324 if (sgdat instanceof SequenceGroup)
326 return ((SequenceGroup) sgdat).getSequencesAsArray(null);
328 if (sgdat instanceof Vector)
330 if (((Vector) sgdat).size() > 0
331 && ((Vector) sgdat).get(0) instanceof SequenceI)
333 SequenceI[] sq = new SequenceI[((Vector) sgdat).size()];
334 ((Vector) sgdat).copyInto(sq);
338 throw new NoValidInputDataException(
339 "No Sequence vector data bound to input '" + token
340 + "' for service at " + rsd.postUrl);
344 * binding between input data (AlignmentI, SequenceGroup, NJTree) and input
347 private Hashtable<String, Object> inputData = new Hashtable<String, Object>();
350 * is the job fully submitted to server and apparently in progress ?
352 public boolean running = false;
358 * - reference to object to be stored as input. Note - input data may
359 * be modifed by formatter
361 public void setAlignmentForInputs(Collection<InputType> itypes,
364 for (InputType itype : itypes)
366 if (!rsd.inputParams.values().contains(itype))
368 throw new IllegalArgumentException("InputType " + itype.getClass()
369 + " is not valid for service at " + rsd.postUrl);
371 if (itype instanceof AlignmentProcessor)
373 ((AlignmentProcessor) itype).prepareAlignment(al);
375 // stash a reference for recall when the alignment data is formatted
376 inputData.put(itype.token, al);
385 * @return alignment object bound to the given token
386 * @throws NoValidInputDataException
388 public AlignmentI getAlignmentForInput(String token,
389 InputType.molType type) throws NoValidInputDataException
391 Object al = inputData.get(token);
392 // can we form an alignment from this data ?
393 if (al == null || !(al instanceof AlignmentI))
395 throw new NoValidInputDataException(
396 "No alignment data bound to input '" + token
397 + "' for service at " + rsd.postUrl);
399 return (AlignmentI) al;
403 * test to see if the job has data of type cl that's needed for the job to run
406 * @return true or false
408 public boolean hasDataOfType(Class cl)
410 if (AlignmentI.class.isAssignableFrom(cl))
414 // TODO: add more source data types
420 * context used to parse results from service
422 JalviewDataset context = null;
424 protected boolean parsedResults = false;
426 protected boolean validJvresults = false;
428 Object[] jvresultobj = null;
431 * process the results obtained from the server into jalview datamodel objects
432 * ready to be merged/added to the users' view. Use hasResults to test if
433 * results were added to context.
435 public void parseResultSet() throws Exception, Error
439 parsedResults = true;
440 jvresultobj = resSet.parseResultSet();
441 validJvresults = true;
447 * @return true if job has an input alignment and it was annotated when
448 * results were parsed
450 public boolean isInputContextModified()
452 return contextAl != null && validJvresults
453 && context.getAl().get(0).isModified();
458 * @return true if the ID/metadata for the input sequences were saved and
459 * sequence IDs renamed.
461 public boolean isInputUniquified()
463 // TODO Auto-generated method stub
468 * Return map between ordering of alignment submitted as input, and ordering
469 * of alignment as provided by user
471 * @return int[sequence index in submitted data]==sequence index in input.
473 public int[] getOrderMap()
475 SequenceI[] contseq = contextAl.getSequencesArray();
476 int map[] = new int[contseq.length];
477 for (int i = 0; i < contseq.length; i++)
479 // TODO: optimise for large N - build a lookup hash for IDs returning
480 // order, and then lookup each sequ's original order
481 map[i] = inputOrder.getOrder().indexOf(contseq[i]);