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()
105 alinp.add(prm.getValue());
114 if ((paramsWithData + alinp.size()) == rsd.inputParams.size())
116 inputOrder = new AlignmentOrder(_input);
117 if ((dsForIO = _input.getDataset()) == null)
119 _input.setDataset(null);
121 dsForIO = _input.getDataset();
126 setAlignmentForInputs(alinp, _input);
131 // not enough data, so we bail.
136 boolean validInput = false;
139 public boolean hasResults()
141 return gotresult && (parsedResults ? validJvresults : true);
145 public boolean hasValidInput()
151 public boolean isRunning()
153 return running; // TODO: can we check the response body for status messages
158 public boolean isQueued()
164 public boolean isFinished()
166 return resSet != null;
170 public boolean isFailed()
172 // TODO logic for error
177 public boolean isBroken()
179 // TODO logic for error
184 public boolean isServerError()
186 // TODO logic for error
191 public boolean hasStatus()
193 return statMessage != null;
196 protected String statMessage = null;
198 public HttpResultSet resSet;
201 public String getStatus()
207 public boolean hasResponse()
209 return statMessage != null || resSet != null;
213 public void clearResponse()
215 // only clear the transient server response
222 * @see jalview.ws.AWsJob#getState()
225 public String getState()
227 // TODO generate state string - prolly should have a default abstract method
229 return "Job is clueless";
232 public String getPostUrl()
235 // TODO Auto-generated method stub
239 public Set<Map.Entry<String, InputType>> getInputParams()
241 return rsd.inputParams.entrySet();
244 // return the URL that should be polled for this job
245 public String getPollUrl()
247 return rsd.getDecoratedResultUrl(jobId);
252 * @return the context for parsing results from service
254 public JalviewDataset newJalviewDataset()
258 context = new JalviewDataset(dsForIO, null, squniq, null);
261 // TODO devise way of merging new annotation onto (identical) existing annotation that was used as input
262 // delete all input annotation
263 if (contextAl.getAlignmentAnnotation()!=null) {
264 for (AlignmentAnnotation alan: contextAl.getAlignmentAnnotation()) {
265 contextAl.deleteAnnotation(alan);
268 // TODO devise way of merging new groups onto (identical) existing groups when they were used as input to service
269 // delete all existing groups
270 if (contextAl.getGroups()!=null)
272 contextAl.deleteAllGroups();
274 context.addAlignment(contextAl);
282 * Extract list of sequence IDs for input parameter 'token' with given
289 public SequenceI[] getSequencesForInput(String token,
290 InputType.molType type) throws NoValidInputDataException
292 Object sgdat = inputData.get(token);
293 // can we form an alignment from this data ?
296 throw new NoValidInputDataException(
297 "No Sequence vector data bound to input '" + token
298 + "' for service at " + rsd.postUrl);
300 if (sgdat instanceof AlignmentI)
302 return ((AlignmentI) sgdat).getSequencesArray();
304 if (sgdat instanceof SequenceGroup)
306 return ((SequenceGroup) sgdat).getSequencesAsArray(null);
308 if (sgdat instanceof Vector)
310 if (((Vector) sgdat).size() > 0
311 && ((Vector) sgdat).get(0) instanceof SequenceI)
313 SequenceI[] sq = new SequenceI[((Vector) sgdat).size()];
314 ((Vector) sgdat).copyInto(sq);
318 throw new NoValidInputDataException(
319 "No Sequence vector data bound to input '" + token
320 + "' for service at " + rsd.postUrl);
324 * binding between input data (AlignmentI, SequenceGroup, NJTree) and input
327 private Hashtable<String, Object> inputData = new Hashtable<String, Object>();
330 * is the job fully submitted to server and apparently in progress ?
332 public boolean running = false;
338 * - reference to object to be stored as input. Note - input data may
339 * be modifed by formatter
341 public void setAlignmentForInputs(Collection<InputType> itypes,
344 for (InputType itype : itypes)
346 if (!rsd.inputParams.values().contains(itype))
348 throw new IllegalArgumentException("InputType " + itype.getClass()
349 + " is not valid for service at " + rsd.postUrl);
351 if (itype instanceof AlignmentProcessor)
353 ((AlignmentProcessor) itype).prepareAlignment(al);
355 // stash a reference for recall when the alignment data is formatted
356 inputData.put(itype.token, al);
365 * @return alignment object bound to the given token
366 * @throws NoValidInputDataException
368 public AlignmentI getAlignmentForInput(String token,
369 InputType.molType type) throws NoValidInputDataException
371 Object al = inputData.get(token);
372 // can we form an alignment from this data ?
373 if (al == null || !(al instanceof AlignmentI))
375 throw new NoValidInputDataException(
376 "No alignment data bound to input '" + token
377 + "' for service at " + rsd.postUrl);
379 return (AlignmentI) al;
383 * test to see if the job has data of type cl that's needed for the job to run
386 * @return true or false
388 public boolean hasDataOfType(Class cl)
390 if (AlignmentI.class.isAssignableFrom(cl))
394 // TODO: add more source data types
400 * context used to parse results from service
402 JalviewDataset context = null;
403 protected boolean parsedResults = false;
404 protected boolean validJvresults=false;
405 Object[] jvresultobj = null;
407 * process the results obtained from the server into jalview datamodel objects
408 * ready to be merged/added to the users' view. Use hasResults to test if results were added to context.
410 public void parseResultSet() throws Exception, Error
412 if (!parsedResults) {
414 jvresultobj = resSet.parseResultSet();
415 validJvresults = true;
421 * @return true if job has an input alignment and it was annotated when results were parsed
423 public boolean isInputContextModified()
425 return contextAl!=null && validJvresults && context.getAl().get(0).isModified();
430 * @return true if the ID/metadata for the input sequences were saved and sequence IDs renamed.
432 public boolean isInputUniquified()
434 // TODO Auto-generated method stub
439 * Return map between ordering of alignment submitted as input, and ordering of alignment as provided by user
440 * @return int[sequence index in submitted data]==sequence index in input.
442 public int[] getOrderMap()
444 SequenceI[] contseq = contextAl.getSequencesArray();
445 int map[] = new int[contseq.length];
446 for (int i=0;i<contseq.length;i++)
448 // TODO: optimise for large N - build a lookup hash for IDs returning order, and then lookup each sequ's original order
449 map[i] = inputOrder.getOrder().indexOf(contseq[i]);