2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ 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
10 * of the License, or (at your option) any later version.
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.
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.
21 package jalview.ws.rest;
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;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Hashtable;
38 import java.util.Vector;
40 public class RestJob extends AWsJob
43 // TODO: input alignmentview and other data for this job
44 RestServiceDescription rsd;
58 * dataset associated with this input data.
62 AlignmentOrder inputOrder;
65 * context of input data with respect to an AlignmentView's visible contigs.
69 private AlignmentI contextAl = null;
72 * create a rest job using data bounded by the given start/end column.
75 * @param restJobThread
78 * visible contigs of an alignment view from which _input was derived
80 public RestJob(int jobNum, RestJobThread restJobThread, AlignmentI _input,
83 rsd = restJobThread.restClient.service;
85 if (viscontigs != null)
87 origviscontig = new int[viscontigs.length];
88 System.arraycopy(viscontigs, 0, origviscontig, 0, viscontigs.length);
90 // get sequences for the alignmentI
91 // get groups trimmed to alignment columns
92 // get any annotation trimmed to start/end columns, too.
93 squniq = jalview.analysis.SeqsetUtils
94 .uniquify(_input.getSequencesArray(), true);
96 // form alignment+groups+annotation,preprocess and then record references
98 ArrayList<InputType> alinp = new ArrayList<InputType>();
99 int paramsWithData = 0;
100 // TODO: JAL-715 - generalise the following validation logic for all
102 // we cheat for moment - since we know a-priori what data is available and
103 // what inputs we have implemented so far
104 for (Map.Entry<String, InputType> prm : rsd.inputParams.entrySet())
106 if (!prm.getValue().isConstant())
108 if (prm.getValue() instanceof Alignment)
110 alinp.add(prm.getValue());
114 if (prm.getValue() instanceof SeqGroupIndexVector
115 && _input.getGroups() != null
116 && _input.getGroups().size() >= -1 + prm.getValue().min)
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 alinp.add(prm.getValue());
125 statMessage = ("Not enough groups defined on the alignment - need at least "
126 + prm.getValue().min);
135 if ((paramsWithData + alinp.size()) == rsd.inputParams.size())
137 inputOrder = new AlignmentOrder(_input);
138 if ((dsForIO = _input.getDataset()) == null)
140 _input.setDataset(null);
142 dsForIO = _input.getDataset();
143 if (contextAl == null)
147 setAlignmentForInputs(alinp, _input);
152 // not enough data, so we bail.
157 boolean validInput = false;
160 public boolean hasResults()
162 return gotresult && (parsedResults ? validJvresults : true);
166 public boolean hasValidInput()
172 public boolean isRunning()
174 return running; // TODO: can we check the response body for status messages
179 public boolean isQueued()
185 public boolean isFinished()
187 return resSet != null;
191 public boolean isFailed()
193 // TODO logic for error
198 public boolean isBroken()
200 // TODO logic for error
205 public boolean isServerError()
207 // TODO logic for error
212 public boolean hasStatus()
214 return statMessage != null;
217 protected String statMessage = null;
219 public HttpResultSet resSet;
222 public String getStatus()
228 public boolean hasResponse()
230 return statMessage != null || resSet != null;
234 public void clearResponse()
236 // only clear the transient server response
243 * @see jalview.ws.AWsJob#getState()
246 public String getState()
248 // TODO generate state string - prolly should have a default abstract method
250 return "Job is clueless";
253 public String getPostUrl()
256 // TODO Auto-generated method stub
260 public Set<Map.Entry<String, InputType>> getInputParams()
262 return rsd.inputParams.entrySet();
265 // return the URL that should be polled for this job
266 public String getPollUrl()
268 return rsd.getDecoratedResultUrl(jobId);
273 * @return the context for parsing results from service
275 public JalviewDataset newJalviewDataset()
279 context = new JalviewDataset(dsForIO, null, squniq, null);
280 if (contextAl != null)
282 // TODO devise way of merging new annotation onto (identical) existing
283 // annotation that was used as input
284 // delete all input annotation
285 if (contextAl.getAlignmentAnnotation() != null)
287 for (AlignmentAnnotation alan : contextAl
288 .getAlignmentAnnotation())
290 contextAl.deleteAnnotation(alan);
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 if (contextAl.getGroups() != null)
298 contextAl.deleteAllGroups();
300 context.addAlignment(contextAl);
308 * Extract list of sequence IDs for input parameter 'token' with given
315 public SequenceI[] getSequencesForInput(String token,
316 InputType.molType type) throws NoValidInputDataException
318 Object sgdat = inputData.get(token);
319 // can we form an alignment from this data ?
322 throw new NoValidInputDataException(
323 "No Sequence vector data bound to input '" + token
324 + "' for service at " + rsd.postUrl);
326 if (sgdat instanceof AlignmentI)
328 return ((AlignmentI) sgdat).getSequencesArray();
330 if (sgdat instanceof SequenceGroup)
332 return ((SequenceGroup) sgdat).getSequencesAsArray(null);
334 if (sgdat instanceof Vector)
336 if (((Vector) sgdat).size() > 0
337 && ((Vector) sgdat).get(0) instanceof SequenceI)
339 SequenceI[] sq = new SequenceI[((Vector) sgdat).size()];
340 ((Vector) sgdat).copyInto(sq);
344 throw new NoValidInputDataException(
345 "No Sequence vector data bound to input '" + token
346 + "' for service at " + rsd.postUrl);
350 * binding between input data (AlignmentI, SequenceGroup, NJTree) and input
353 private Hashtable<String, Object> inputData = new Hashtable<String, Object>();
356 * is the job fully submitted to server and apparently in progress ?
358 public boolean running = false;
364 * - reference to object to be stored as input. Note - input data may
365 * be modifed by formatter
367 public void setAlignmentForInputs(Collection<InputType> itypes,
370 for (InputType itype : itypes)
372 if (!rsd.inputParams.values().contains(itype))
374 throw new IllegalArgumentException("InputType " + itype.getClass()
375 + " is not valid for service at " + rsd.postUrl);
377 if (itype instanceof AlignmentProcessor)
379 ((AlignmentProcessor) itype).prepareAlignment(al);
381 // stash a reference for recall when the alignment data is formatted
382 inputData.put(itype.token, al);
391 * @return alignment object bound to the given token
392 * @throws NoValidInputDataException
394 public AlignmentI getAlignmentForInput(String token,
395 InputType.molType type) throws NoValidInputDataException
397 Object al = inputData.get(token);
398 // can we form an alignment from this data ?
399 if (al == null || !(al instanceof AlignmentI))
401 throw new NoValidInputDataException(
402 "No alignment data bound to input '" + token
403 + "' for service at " + rsd.postUrl);
405 return (AlignmentI) al;
409 * test to see if the job has data of type cl that's needed for the job to run
412 * @return true or false
414 public boolean hasDataOfType(Class cl)
416 if (AlignmentI.class.isAssignableFrom(cl))
420 // TODO: add more source data types
426 * context used to parse results from service
428 JalviewDataset context = null;
430 protected boolean parsedResults = false;
432 protected boolean validJvresults = false;
434 Object[] jvresultobj = null;
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.
441 public void parseResultSet() throws Exception, Error
445 parsedResults = true;
446 jvresultobj = resSet.parseResultSet();
447 validJvresults = true;
453 * @return true if job has an input alignment and it was annotated when
454 * results were parsed
456 public boolean isInputContextModified()
458 return contextAl != null && validJvresults
459 && context.getAl().get(0).isModified();
464 * @return true if the ID/metadata for the input sequences were saved and
465 * sequence IDs renamed.
467 public boolean isInputUniquified()
469 // TODO Auto-generated method stub
474 * Return map between ordering of alignment submitted as input, and ordering
475 * of alignment as provided by user
477 * @return int[sequence index in submitted data]==sequence index in input.
479 public int[] getOrderMap()
481 SequenceI[] contseq = contextAl.getSequencesArray();
482 int map[] = new int[contseq.length];
483 for (int i = 0; i < contseq.length; i++)
485 // TODO: optimise for large N - build a lookup hash for IDs returning
486 // order, and then lookup each sequ's original order
487 map[i] = inputOrder.getOrder().indexOf(contseq[i]);