1 package jalview.ws.rest;
3 import java.io.IOException;
4 import java.sql.ResultSet;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.Hashtable;
10 import java.util.Map.Entry;
12 import java.util.Vector;
14 import jalview.datamodel.AlignmentAnnotation;
15 import jalview.datamodel.AlignmentI;
16 import jalview.datamodel.AlignmentOrder;
17 import jalview.datamodel.AlignmentView;
18 import jalview.datamodel.SequenceGroup;
19 import jalview.datamodel.SequenceI;
20 import jalview.io.packed.DataProvider;
21 import jalview.io.packed.JalviewDataset;
22 import jalview.io.packed.ParsePackedSet;
23 import jalview.io.packed.SimpleDataProvider;
24 import jalview.io.packed.DataProvider.JvDataType;
25 import jalview.ws.AWsJob;
26 import jalview.ws.rest.params.Alignment;
27 import jalview.ws.rest.params.SeqGroupIndexVector;
29 public class RestJob extends AWsJob
32 // TODO: input alignmentview and other data for this job
33 RestServiceDescription rsd;
47 * dataset associated with this input data.
51 AlignmentOrder inputOrder;
54 * context of input data with respect to an AlignmentView's visible contigs.
58 private AlignmentI contextAl=null;
61 * create a rest job using data bounded by the given start/end column.
64 * @param restJobThread
67 * visible contigs of an alignment view from which _input was derived
69 public RestJob(int jobNum, RestJobThread restJobThread,
70 AlignmentI _input, int[] viscontigs)
72 rsd = restJobThread.restClient.service;
74 if (viscontigs != null)
76 origviscontig = new int[viscontigs.length];
77 System.arraycopy(viscontigs, 0, origviscontig, 0, viscontigs.length);
79 // get sequences for the alignmentI
80 // get groups trimmed to alignment columns
81 // get any annotation trimmed to start/end columns, too.
84 // form alignment+groups+annotation,preprocess and then record references
86 ArrayList<InputType> alinp = new ArrayList<InputType>();
87 int paramsWithData = 0;
88 // we cheat for moment - since we know a-priori what data is available and
89 // what inputs we have implemented so far
90 for (Map.Entry<String, InputType> prm : rsd.inputParams.entrySet())
92 if (!prm.getValue().isConstant())
94 if (prm.getValue() instanceof Alignment)
96 alinp.add(prm.getValue());
100 // TODO: move validation of input data to SeqGroupIndexVector
101 if ((prm.getValue() instanceof SeqGroupIndexVector)
102 && (_input.getGroups() != null && _input.getGroups()
103 .size() >= prm.getValue().min))
105 alinp.add(prm.getValue());
107 statMessage=("Not enough groups defined on the alignment - need at least "+prm.getValue().min);
116 if ((paramsWithData + alinp.size()) == rsd.inputParams.size())
118 inputOrder = new AlignmentOrder(_input);
119 if ((dsForIO = _input.getDataset()) == null)
121 _input.setDataset(null);
123 dsForIO = _input.getDataset();
128 setAlignmentForInputs(alinp, _input);
133 // not enough data, so we bail.
138 boolean validInput = false;
141 public boolean hasResults()
143 return gotresult && (parsedResults ? validJvresults : true);
147 public boolean hasValidInput()
153 public boolean isRunning()
155 return running; // TODO: can we check the response body for status messages
160 public boolean isQueued()
166 public boolean isFinished()
168 return resSet != null;
172 public boolean isFailed()
174 // TODO logic for error
179 public boolean isBroken()
181 // TODO logic for error
186 public boolean isServerError()
188 // TODO logic for error
193 public boolean hasStatus()
195 return statMessage != null;
198 protected String statMessage = null;
200 public HttpResultSet resSet;
203 public String getStatus()
209 public boolean hasResponse()
211 return statMessage != null || resSet != null;
215 public void clearResponse()
217 // only clear the transient server response
224 * @see jalview.ws.AWsJob#getState()
227 public String getState()
229 // TODO generate state string - prolly should have a default abstract method
231 return "Job is clueless";
234 public String getPostUrl()
237 // TODO Auto-generated method stub
241 public Set<Map.Entry<String, InputType>> getInputParams()
243 return rsd.inputParams.entrySet();
246 // return the URL that should be polled for this job
247 public String getPollUrl()
249 return rsd.getDecoratedResultUrl(jobId);
254 * @return the context for parsing results from service
256 public JalviewDataset newJalviewDataset()
260 context = new JalviewDataset(dsForIO, null, squniq, null);
263 // TODO devise way of merging new annotation onto (identical) existing annotation that was used as input
264 // delete all input annotation
265 if (contextAl.getAlignmentAnnotation()!=null) {
266 for (AlignmentAnnotation alan: contextAl.getAlignmentAnnotation()) {
267 contextAl.deleteAnnotation(alan);
270 // TODO devise way of merging new groups onto (identical) existing groups when they were used as input to service
271 // delete all existing groups
272 if (contextAl.getGroups()!=null)
274 contextAl.deleteAllGroups();
276 context.addAlignment(contextAl);
284 * Extract list of sequence IDs for input parameter 'token' with given
291 public SequenceI[] getSequencesForInput(String token,
292 InputType.molType type) throws NoValidInputDataException
294 Object sgdat = inputData.get(token);
295 // can we form an alignment from this data ?
298 throw new NoValidInputDataException(
299 "No Sequence vector data bound to input '" + token
300 + "' for service at " + rsd.postUrl);
302 if (sgdat instanceof AlignmentI)
304 return ((AlignmentI) sgdat).getSequencesArray();
306 if (sgdat instanceof SequenceGroup)
308 return ((SequenceGroup) sgdat).getSequencesAsArray(null);
310 if (sgdat instanceof Vector)
312 if (((Vector) sgdat).size() > 0
313 && ((Vector) sgdat).get(0) instanceof SequenceI)
315 SequenceI[] sq = new SequenceI[((Vector) sgdat).size()];
316 ((Vector) sgdat).copyInto(sq);
320 throw new NoValidInputDataException(
321 "No Sequence vector data bound to input '" + token
322 + "' for service at " + rsd.postUrl);
326 * binding between input data (AlignmentI, SequenceGroup, NJTree) and input
329 private Hashtable<String, Object> inputData = new Hashtable<String, Object>();
332 * is the job fully submitted to server and apparently in progress ?
334 public boolean running = false;
340 * - reference to object to be stored as input. Note - input data may
341 * be modifed by formatter
343 public void setAlignmentForInputs(Collection<InputType> itypes,
346 for (InputType itype : itypes)
348 if (!rsd.inputParams.values().contains(itype))
350 throw new IllegalArgumentException("InputType " + itype.getClass()
351 + " is not valid for service at " + rsd.postUrl);
353 if (itype instanceof AlignmentProcessor)
355 ((AlignmentProcessor) itype).prepareAlignment(al);
357 // stash a reference for recall when the alignment data is formatted
358 inputData.put(itype.token, al);
367 * @return alignment object bound to the given token
368 * @throws NoValidInputDataException
370 public AlignmentI getAlignmentForInput(String token,
371 InputType.molType type) throws NoValidInputDataException
373 Object al = inputData.get(token);
374 // can we form an alignment from this data ?
375 if (al == null || !(al instanceof AlignmentI))
377 throw new NoValidInputDataException(
378 "No alignment data bound to input '" + token
379 + "' for service at " + rsd.postUrl);
381 return (AlignmentI) al;
385 * test to see if the job has data of type cl that's needed for the job to run
388 * @return true or false
390 public boolean hasDataOfType(Class cl)
392 if (AlignmentI.class.isAssignableFrom(cl))
396 // TODO: add more source data types
402 * context used to parse results from service
404 JalviewDataset context = null;
405 protected boolean parsedResults = false;
406 protected boolean validJvresults=false;
407 Object[] jvresultobj = null;
409 * process the results obtained from the server into jalview datamodel objects
410 * ready to be merged/added to the users' view. Use hasResults to test if results were added to context.
412 public void parseResultSet() throws Exception, Error
414 if (!parsedResults) {
416 jvresultobj = resSet.parseResultSet();
417 validJvresults = true;
423 * @return true if job has an input alignment and it was annotated when results were parsed
425 public boolean isInputContextModified()
427 return contextAl!=null && validJvresults && context.getAl().get(0).isModified();
432 * @return true if the ID/metadata for the input sequences were saved and sequence IDs renamed.
434 public boolean isInputUniquified()
436 // TODO Auto-generated method stub
441 * Return map between ordering of alignment submitted as input, and ordering of alignment as provided by user
442 * @return int[sequence index in submitted data]==sequence index in input.
444 public int[] getOrderMap()
446 SequenceI[] contseq = contextAl.getSequencesArray();
447 int map[] = new int[contseq.length];
448 for (int i=0;i<contseq.length;i++)
450 // TODO: optimise for large N - build a lookup hash for IDs returning order, and then lookup each sequ's original order
451 map[i] = inputOrder.getOrder().indexOf(contseq[i]);