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;
62 Vector<String[]> emptySeqs = new Vector();
65 * prepare input sequences for MsaWS service
68 * jalview sequences to be prepared
70 * minimum number of residues required for this MsaWS service
71 * @return true if seqs contains sequences to be submitted to service.
73 // TODO: return compbio.seqs list or nothing to indicate validity.
74 private boolean prepareInput(SequenceI[] seqs, int minlen)
76 // TODO: service specific input data is generated in this method - for
77 // JABAWS it is client-side
78 // prepared, but for Slivka it could be uploaded at this stage.
83 throw new Error(MessageManager.getString(
84 "error.implementation_error_minlen_must_be_greater_zero"));
86 for (int i = 0; i < seqs.length; i++)
88 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
93 boolean valid = nseqs > 1; // need at least two seqs
95 for (int i = 0, n = 0; i < seqs.length; i++)
97 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
101 SeqNames.put(newname,
102 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
103 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
105 // make new input sequence with or without gaps
106 seq = new Sequence(newname,
107 (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString()
108 : AlignSeq.extractGaps(
109 jalview.util.Comparison.GapChars,
110 seqs[i].getSequenceAsString()));
116 if (seqs[i].getEnd() >= seqs[i].getStart())
118 empty = (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString()
119 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
120 seqs[i].getSequenceAsString());
122 emptySeqs.add(new String[] { newname, empty });
130 * @return true if getAlignment will return a valid alignment result.
133 public boolean hasResults()
135 if (subjobComplete && isFinished() && (alignment != null
136 || (emptySeqs != null && emptySeqs.size() > 0)))
145 * get the alignment including any empty sequences in the original order
146 * with original ids. Caller must access the alignment.getMetadata() object
147 * to annotate the final result passsed to the user.
149 * @return { SequenceI[], AlignmentOrder }
151 public Object[] getAlignment()
153 // TODO: make this generic based on MsaResultI
154 // TODO: decide if the data loss for this return signature is avoidable
155 // (ie should we just return AlignmentI instead ?)
158 SequenceI[] alseqs = null;
159 char alseq_gapchar = '-';
161 alseqs = new SequenceI[alignment.getSequences().size()];
162 if (alignment.getSequences().size() > 0)
164 for (SequenceI seq : alignment
167 alseqs[alseq_l++] = new Sequence(seq);
169 alseq_gapchar = alignment.getGapCharacter();
172 // add in the empty seqs.
173 if (emptySeqs.size() > 0)
175 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
180 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
182 if (w < alseqs[i].getLength())
184 w = alseqs[i].getLength();
186 t_alseqs[i] = alseqs[i];
190 // check that aligned width is at least as wide as emptySeqs width.
192 for (i = 0, w = emptySeqs.size(); i < w; i++)
194 String[] es = emptySeqs.get(i);
195 if (es != null && es[1] != null)
197 int sw = es[1].length();
204 // make a gapped string.
205 StringBuffer insbuff = new StringBuffer(w);
206 for (i = 0; i < nw; i++)
208 insbuff.append(alseq_gapchar);
212 for (i = 0; i < alseq_l; i++)
214 int sw = t_alseqs[i].getLength();
218 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
219 + insbuff.substring(0, sw - nw));
223 for (i = 0, w = emptySeqs.size(); i < w; i++)
225 String[] es = emptySeqs.get(i);
228 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
229 insbuff.toString(), 1, 0);
233 if (es[1].length() < nw)
235 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
237 es[1] + insbuff.substring(0, nw - es[1].length()),
238 1, 1 + es[1].length());
242 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
249 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
250 // always recover the order - makes parseResult()'s life easier.
251 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
252 // account for any missing sequences
253 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
254 return new Object[] { alseqs, msaorder };
260 * mark subjob as cancelled and set result object appropriatly
265 subjobComplete = true;
271 * @return boolean true if job can be submitted.
274 public boolean hasValidInput()
276 // TODO: get attributes for this MsaWS instance to check if it can do two
277 // sequence alignment.
278 if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ?
285 StringBuffer jobProgress = new StringBuffer();
288 public void setStatus(String string)
290 jobProgress.setLength(0);
291 jobProgress.append(string);
295 public String getStatus()
297 return jobProgress.toString();
301 public boolean hasStatus()
303 return jobProgress != null;
307 * @return the lastChunk
309 public long getLastChunk()
316 * the lastChunk to set
318 public void setLastChunk(long lastChunk)
320 this.lastChunk = lastChunk;
323 String alignmentProgram = null;
325 public String getAlignmentProgram()
327 return alignmentProgram;
330 public boolean hasArguments()
332 return (arguments != null && arguments.size() > 0)
333 || (preset != null && preset instanceof JabaWsParamSet);
337 * add a progess header to status string containing presets/args used
339 public void addInitialStatus()
341 // TODO: decide if it is useful to report 'JABAWS format' argument lists
342 // rather than generic Jalview service arguments
346 "Using " + (preset.isModifiable() ? "Server" : "User")
347 + "Preset: " + preset.getName());
348 for (ArgumentI opt : preset.getArguments())
350 jobProgress.append(opt.getName() + " " + opt.getValue() + "\n");
355 if (arguments != null && arguments.size() > 0)
357 jobProgress.append("With custom parameters : \n");
358 // merge arguments with preset's own arguments.
359 for (ArgumentI opt : arguments)
361 jobProgress.append(opt.getName() + " " + opt.getValue() + "\n");
364 jobProgress.append("\nJob Output:\n");
368 JobId jobHandle = null;
369 public void setJobHandle(JobId align)
372 setJobId(jobHandle.getJobId());
376 public JobId getJobHandle()