1 package jalview.ws.gui;
3 import jalview.analysis.AlignSeq;
4 import jalview.datamodel.AlignmentI;
5 import jalview.datamodel.AlignmentOrder;
6 import jalview.datamodel.Sequence;
7 import jalview.datamodel.SequenceI;
8 import jalview.util.MessageManager;
9 import jalview.ws.api.JobId;
10 import jalview.ws.jws2.dm.JabaWsParamSet;
11 import jalview.ws.params.ArgumentI;
13 import java.util.ArrayList;
14 import java.util.Vector;
16 class MsaWSJob extends WsJob
19 * holds basic MSA analysis configuration - todo - encapsulate
21 private final MsaWSThread msaWSThread;
28 ArrayList<SequenceI> seqs = new ArrayList<>();
35 // set if the job didn't get run - then the input is simply returned to the
37 private boolean returnInput = false;
45 * TODO - abstract the properties provided by the thread
49 public MsaWSJob(MsaWSThread msaWSThread, int jobNum, SequenceI[] inSeqs)
51 this.msaWSThread = msaWSThread;
53 if (!prepareInput(inSeqs, 2))
56 subjobComplete = true;
65 Vector<String[]> emptySeqs = new Vector();
68 * prepare input sequences for MsaWS service
71 * jalview sequences to be prepared
73 * minimum number of residues required for this MsaWS service
74 * @return true if seqs contains sequences to be submitted to service.
76 // TODO: return compbio.seqs list or nothing to indicate validity.
77 private boolean prepareInput(SequenceI[] seqs, int minlen)
79 // TODO: service specific input data is generated in this method - for
80 // JABAWS it is client-side
81 // prepared, but for Slivka it could be uploaded at this stage.
86 throw new Error(MessageManager.getString(
87 "error.implementation_error_minlen_must_be_greater_zero"));
89 for (int i = 0; i < seqs.length; i++)
91 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
96 boolean valid = nseqs > 1; // need at least two seqs
98 for (int i = 0, n = 0; i < seqs.length; i++)
100 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
104 SeqNames.put(newname,
105 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
106 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
108 // make new input sequence with or without gaps
109 seq = new Sequence(newname,
110 (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString()
111 : AlignSeq.extractGaps(
112 jalview.util.Comparison.GapChars,
113 seqs[i].getSequenceAsString()));
119 if (seqs[i].getEnd() >= seqs[i].getStart())
121 empty = (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString()
122 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
123 seqs[i].getSequenceAsString());
125 emptySeqs.add(new String[] { newname, empty });
133 * @return true if getAlignment will return a valid alignment result.
136 public boolean hasResults()
138 if (subjobComplete && isFinished() && (alignment != null
139 || (emptySeqs != null && emptySeqs.size() > 0)))
148 * get the alignment including any empty sequences in the original order
149 * with original ids. Caller must access the alignment.getMetadata() object
150 * to annotate the final result passsed to the user.
152 * @return { SequenceI[], AlignmentOrder }
154 public Object[] getAlignment()
156 // TODO: make this generic based on MsaResultI
157 // TODO: decide if the data loss for this return signature is avoidable
158 // (ie should we just return AlignmentI instead ?)
161 SequenceI[] alseqs = null;
162 char alseq_gapchar = '-';
164 alseqs = new SequenceI[alignment.getSequences().size()];
165 if (alignment.getSequences().size() > 0)
167 for (SequenceI seq : alignment
170 alseqs[alseq_l++] = new Sequence(seq);
172 alseq_gapchar = alignment.getGapCharacter();
175 // add in the empty seqs.
176 if (emptySeqs.size() > 0)
178 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
183 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
185 if (w < alseqs[i].getLength())
187 w = alseqs[i].getLength();
189 t_alseqs[i] = alseqs[i];
193 // check that aligned width is at least as wide as emptySeqs width.
195 for (i = 0, w = emptySeqs.size(); i < w; i++)
197 String[] es = emptySeqs.get(i);
198 if (es != null && es[1] != null)
200 int sw = es[1].length();
207 // make a gapped string.
208 StringBuffer insbuff = new StringBuffer(w);
209 for (i = 0; i < nw; i++)
211 insbuff.append(alseq_gapchar);
215 for (i = 0; i < alseq_l; i++)
217 int sw = t_alseqs[i].getLength();
221 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
222 + insbuff.substring(0, sw - nw));
226 for (i = 0, w = emptySeqs.size(); i < w; i++)
228 String[] es = emptySeqs.get(i);
231 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
232 insbuff.toString(), 1, 0);
236 if (es[1].length() < nw)
238 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
240 es[1] + insbuff.substring(0, nw - es[1].length()),
241 1, 1 + es[1].length());
245 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
252 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
253 // always recover the order - makes parseResult()'s life easier.
254 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
255 // account for any missing sequences
256 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
257 return new Object[] { alseqs, msaorder };
263 * mark subjob as cancelled and set result object appropriatly
268 subjobComplete = true;
274 * @return boolean true if job can be submitted.
277 public boolean hasValidInput()
279 // TODO: get attributes for this MsaWS instance to check if it can do two
280 // sequence alignment.
281 if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ?
288 StringBuffer jobProgress = new StringBuffer();
291 public void setStatus(String string)
293 jobProgress.setLength(0);
294 jobProgress.append(string);
298 public String getStatus()
300 return jobProgress.toString();
304 public boolean hasStatus()
306 return jobProgress != null;
310 * @return the lastChunk
312 public long getLastChunk()
319 * the lastChunk to set
321 public void setLastChunk(long lastChunk)
323 this.lastChunk = lastChunk;
326 String alignmentProgram = null;
328 public String getAlignmentProgram()
330 return alignmentProgram;
333 public boolean hasArguments()
335 return (arguments != null && arguments.size() > 0)
336 || (preset != null && preset instanceof JabaWsParamSet);
340 * add a progess header to status string containing presets/args used
342 public void addInitialStatus()
344 // TODO: decide if it is useful to report 'JABAWS format' argument lists
345 // rather than generic Jalview service arguments
349 "Using " + (preset.isModifiable() ? "Server" : "User")
350 + "Preset: " + preset.getName());
351 for (ArgumentI opt : preset.getArguments())
353 jobProgress.append(opt.getName() + " " + opt.getValue() + "\n");
358 if (arguments != null && arguments.size() > 0)
360 jobProgress.append("With custom parameters : \n");
361 // merge arguments with preset's own arguments.
362 for (ArgumentI opt : arguments)
364 jobProgress.append(opt.getName() + " " + opt.getValue() + "\n");
367 jobProgress.append("\nJob Output:\n");
371 JobId jobHandle = null;
372 public void setJobHandle(JobId align)
375 setJobId(jobHandle.getJobId());
379 public JobId getJobHandle()