2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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/>.
18 package jalview.ws.rest;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Hashtable;
25 import java.util.Vector;
27 import jalview.datamodel.AlignmentAnnotation;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.AlignmentOrder;
30 import jalview.datamodel.SequenceGroup;
31 import jalview.datamodel.SequenceI;
32 import jalview.io.packed.JalviewDataset;
33 import jalview.ws.AWsJob;
34 import jalview.ws.rest.params.Alignment;
35 import jalview.ws.rest.params.SeqGroupIndexVector;
37 public class RestJob extends AWsJob
40 // TODO: input alignmentview and other data for this job
41 RestServiceDescription rsd;
55 * dataset associated with this input data.
59 AlignmentOrder inputOrder;
62 * context of input data with respect to an AlignmentView's visible contigs.
66 private AlignmentI contextAl = null;
69 * create a rest job using data bounded by the given start/end column.
72 * @param restJobThread
75 * visible contigs of an alignment view from which _input was derived
77 public RestJob(int jobNum, RestJobThread restJobThread,
78 AlignmentI _input, int[] viscontigs)
80 rsd = restJobThread.restClient.service;
82 if (viscontigs != null)
84 origviscontig = new int[viscontigs.length];
85 System.arraycopy(viscontigs, 0, origviscontig, 0, viscontigs.length);
87 // get sequences for the alignmentI
88 // get groups trimmed to alignment columns
89 // get any annotation trimmed to start/end columns, too.
92 // form alignment+groups+annotation,preprocess and then record references
94 ArrayList<InputType> alinp = new ArrayList<InputType>();
95 int paramsWithData = 0;
96 // we cheat for moment - since we know a-priori what data is available and
97 // what inputs we have implemented so far
98 for (Map.Entry<String, InputType> prm : rsd.inputParams.entrySet())
100 if (!prm.getValue().isConstant())
102 if (prm.getValue() instanceof Alignment)
104 alinp.add(prm.getValue());
108 // TODO: move validation of input data to SeqGroupIndexVector
109 if ((prm.getValue() instanceof SeqGroupIndexVector)
110 && (_input.getGroups() != null && _input.getGroups()
111 .size() >= prm.getValue().min))
113 alinp.add(prm.getValue());
117 statMessage = ("Not enough groups defined on the alignment - need at least " + prm
127 if ((paramsWithData + alinp.size()) == rsd.inputParams.size())
129 inputOrder = new AlignmentOrder(_input);
130 if ((dsForIO = _input.getDataset()) == null)
132 _input.setDataset(null);
134 dsForIO = _input.getDataset();
135 if (contextAl == null)
139 setAlignmentForInputs(alinp, _input);
144 // not enough data, so we bail.
149 boolean validInput = false;
152 public boolean hasResults()
154 return gotresult && (parsedResults ? validJvresults : true);
158 public boolean hasValidInput()
164 public boolean isRunning()
166 return running; // TODO: can we check the response body for status messages
171 public boolean isQueued()
177 public boolean isFinished()
179 return resSet != null;
183 public boolean isFailed()
185 // TODO logic for error
190 public boolean isBroken()
192 // TODO logic for error
197 public boolean isServerError()
199 // TODO logic for error
204 public boolean hasStatus()
206 return statMessage != null;
209 protected String statMessage = null;
211 public HttpResultSet resSet;
214 public String getStatus()
220 public boolean hasResponse()
222 return statMessage != null || resSet != null;
226 public void clearResponse()
228 // only clear the transient server response
235 * @see jalview.ws.AWsJob#getState()
238 public String getState()
240 // TODO generate state string - prolly should have a default abstract method
242 return "Job is clueless";
245 public String getPostUrl()
248 // TODO Auto-generated method stub
252 public Set<Map.Entry<String, InputType>> getInputParams()
254 return rsd.inputParams.entrySet();
257 // return the URL that should be polled for this job
258 public String getPollUrl()
260 return rsd.getDecoratedResultUrl(jobId);
265 * @return the context for parsing results from service
267 public JalviewDataset newJalviewDataset()
271 context = new JalviewDataset(dsForIO, null, squniq, null);
272 if (contextAl != null)
274 // TODO devise way of merging new annotation onto (identical) existing
275 // annotation that was used as input
276 // delete all input annotation
277 if (contextAl.getAlignmentAnnotation() != null)
279 for (AlignmentAnnotation alan : contextAl
280 .getAlignmentAnnotation())
282 contextAl.deleteAnnotation(alan);
285 // TODO devise way of merging new groups onto (identical) existing
286 // groups when they were used as input to service
287 // delete all existing groups
288 if (contextAl.getGroups() != null)
290 contextAl.deleteAllGroups();
292 context.addAlignment(contextAl);
300 * Extract list of sequence IDs for input parameter 'token' with given
307 public SequenceI[] getSequencesForInput(String token,
308 InputType.molType type) throws NoValidInputDataException
310 Object sgdat = inputData.get(token);
311 // can we form an alignment from this data ?
314 throw new NoValidInputDataException(
315 "No Sequence vector data bound to input '" + token
316 + "' for service at " + rsd.postUrl);
318 if (sgdat instanceof AlignmentI)
320 return ((AlignmentI) sgdat).getSequencesArray();
322 if (sgdat instanceof SequenceGroup)
324 return ((SequenceGroup) sgdat).getSequencesAsArray(null);
326 if (sgdat instanceof Vector)
328 if (((Vector) sgdat).size() > 0
329 && ((Vector) sgdat).get(0) instanceof SequenceI)
331 SequenceI[] sq = new SequenceI[((Vector) sgdat).size()];
332 ((Vector) sgdat).copyInto(sq);
336 throw new NoValidInputDataException(
337 "No Sequence vector data bound to input '" + token
338 + "' for service at " + rsd.postUrl);
342 * binding between input data (AlignmentI, SequenceGroup, NJTree) and input
345 private Hashtable<String, Object> inputData = new Hashtable<String, Object>();
348 * is the job fully submitted to server and apparently in progress ?
350 public boolean running = false;
356 * - reference to object to be stored as input. Note - input data may
357 * be modifed by formatter
359 public void setAlignmentForInputs(Collection<InputType> itypes,
362 for (InputType itype : itypes)
364 if (!rsd.inputParams.values().contains(itype))
366 throw new IllegalArgumentException("InputType " + itype.getClass()
367 + " is not valid for service at " + rsd.postUrl);
369 if (itype instanceof AlignmentProcessor)
371 ((AlignmentProcessor) itype).prepareAlignment(al);
373 // stash a reference for recall when the alignment data is formatted
374 inputData.put(itype.token, al);
383 * @return alignment object bound to the given token
384 * @throws NoValidInputDataException
386 public AlignmentI getAlignmentForInput(String token,
387 InputType.molType type) throws NoValidInputDataException
389 Object al = inputData.get(token);
390 // can we form an alignment from this data ?
391 if (al == null || !(al instanceof AlignmentI))
393 throw new NoValidInputDataException(
394 "No alignment data bound to input '" + token
395 + "' for service at " + rsd.postUrl);
397 return (AlignmentI) al;
401 * test to see if the job has data of type cl that's needed for the job to run
404 * @return true or false
406 public boolean hasDataOfType(Class cl)
408 if (AlignmentI.class.isAssignableFrom(cl))
412 // TODO: add more source data types
418 * context used to parse results from service
420 JalviewDataset context = null;
422 protected boolean parsedResults = false;
424 protected boolean validJvresults = false;
426 Object[] jvresultobj = null;
429 * process the results obtained from the server into jalview datamodel objects
430 * ready to be merged/added to the users' view. Use hasResults to test if
431 * results were added to context.
433 public void parseResultSet() throws Exception, Error
437 parsedResults = true;
438 jvresultobj = resSet.parseResultSet();
439 validJvresults = true;
445 * @return true if job has an input alignment and it was annotated when
446 * results were parsed
448 public boolean isInputContextModified()
450 return contextAl != null && validJvresults
451 && context.getAl().get(0).isModified();
456 * @return true if the ID/metadata for the input sequences were saved and
457 * sequence IDs renamed.
459 public boolean isInputUniquified()
461 // TODO Auto-generated method stub
466 * Return map between ordering of alignment submitted as input, and ordering
467 * of alignment as provided by user
469 * @return int[sequence index in submitted data]==sequence index in input.
471 public int[] getOrderMap()
473 SequenceI[] contseq = contextAl.getSequencesArray();
474 int map[] = new int[contseq.length];
475 for (int i = 0; i < contseq.length; i++)
477 // TODO: optimise for large N - build a lookup hash for IDs returning
478 // order, and then lookup each sequ's original order
479 map[i] = inputOrder.getOrder().indexOf(contseq[i]);