package jalview.ws;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
import jalview.gui.WebserviceInfo;
import jalview.analysis.AlignSeq;
import jalview.bin.Cache;
import jalview.gui.AlignFrame;
import javax.swing.JOptionPane;
import vamsas.objects.simple.MsaResult;
import vamsas.objects.simple.Result;
import jalview.datamodel.Alignment;
import jalview.datamodel.SeqCigar;
import jalview.gui.Desktop;
import jalview.datamodel.SequenceI;
import java.util.Hashtable;
import java.util.Vector;
/**
*
* Title:
*
*
*
* Description:
*
*
*
* Copyright: Copyright (c) 2004
*
*
*
* Company: Dundee University
*
*
* @author not attributable
* @version 1.0
*/
class MsaWSThread extends Thread implements WSClientI {
jalview.gui.AlignFrame alignFrame;
WebserviceInfo wsInfo = null;
String WebServiceName = null;
String OutputHeader;
AlignmentView input;
boolean submitGaps = false; // pass sequences including gaps to alignment
// service
boolean preserveOrder = true; // and always store and recover sequence
// order
class MsaWSJob {
int jobnum = 0; // WebServiceInfo pane for this job
String jobId; // ws job ticket
vamsas.objects.simple.MsaResult result = null;
vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
/**
* MsaWSJob
*
* @param jobNum
* int
* @param jobId
* String
*/
public MsaWSJob(int jobNum, SequenceI[] inSeqs) {
this.jobnum = jobNum;
if (!prepareInput(inSeqs,2)) {
submitted=true;
subjobComplete=true;
result = new MsaResult();
result.setFinished(true);
result.setStatus("Job never ran - input returned to user.");
}
}
int allowedServerExceptions = 3; // thread dies if too many
// exceptions.
boolean submitted=false;
boolean subjobComplete = false;
Hashtable SeqNames = new Hashtable();
Vector emptySeqs = new Vector();
/**
* prepare input sequences for MsaWS service
* @param seqs jalview sequences to be prepared
* @param minlen minimum number of residues required for this MsaWS service
* @return true if seqs contains sequences to be submitted to service.
*/
private boolean prepareInput(SequenceI[] seqs, int minlen) {
int nseqs = 0;
if (minlen<0)
throw new Error("Implementation error: minlen must be zero or more.");
for (int i = 0; i < seqs.length; i++) {
if (seqs[i].getEnd()-seqs[i].getStart()>minlen-1) {
nseqs++;
}
}
boolean valid=nseqs>1; // need at least two seqs
vamsas.objects.simple.Sequence[] seqarray =
(valid)
? new vamsas.objects.simple.Sequence[nseqs]
:null;
for (int i = 0, n = 0; i < seqs.length; i++) {
String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
// for
// any
// subjob
SeqNames.put(newname, jalview.analysis.SeqsetUtils
.SeqCharacterHash(seqs[i]));
if (valid && seqs[i].getEnd()-seqs[i].getStart()>minlen-1) {
seqarray[n] = new vamsas.objects.simple.Sequence();
seqarray[n].setId(newname);
seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequence()
: AlignSeq.extractGaps(
jalview.util.Comparison.GapChars, seqs[i]
.getSequence()));
} else {
String empty=null;
if (seqs[i].getEnd()>=seqs[i].getStart()) {
empty = (submitGaps) ? seqs[i].getSequence()
: AlignSeq.extractGaps(
jalview.util.Comparison.GapChars, seqs[i]
.getSequence());
}
emptySeqs.add(new String[] { newname, empty});
}
}
this.seqs = new vamsas.objects.simple.SequenceSet();
this.seqs.setSeqs(seqarray);
return valid;
}
/**
*
* @return true if getAlignment will return a valid alignment result.
*/
public boolean hasResults() {
if (subjobComplete && result!=null && jobs[0].result.isFinished())
return true;
return false;
}
public Object[] getAlignment() {
if (result!=null && result.isFinished()) {
SequenceI[] alseqs=null;
char alseq_gapchar='-';
int alseq_l=0;
if (result.getMsa() != null) {
alseqs = getVamsasAlignment(result.getMsa());
alseq_gapchar=result.getMsa().getGapchar().charAt(0);
alseq_l = alseqs.length;
}
if (emptySeqs.size()>0) {
SequenceI[] t_alseqs = new SequenceI[alseq_l+emptySeqs.size()];
// get width
int i,w=0;
if (alseq_l>0) {
for (i=0,w=alseqs[0].getLength(); isw) {
// pad at end
alseqs[i].setSequence(t_alseqs[i].getSequence()+insbuff.substring(0,sw-nw));
}
}
}
for (i=0, w=emptySeqs.size(); i 0) {
int start = 0;
njobs=0;
int width = _msa.getWidth();
for (int contig = 0; contig < contigs.length; contig += 3) {
if ((contigs[contig+1] - start) > 0) {
njobs++;
}
width+=contigs[contig+2];// end up with full region width (including hidden regions)
start = contigs[contig+1] + contigs[contig + 2];
}
if (start 0) {
SequenceI mseq[] = new SequenceI[msa.length];
for (int s = 0; s < mseq.length; s++) {
mseq[s] = msa[s].getSeq('-').getSubSequence(start,
contigs[contig+1]);
}
if (j!=0) {
jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
} else {
jobs[j] = new MsaWSJob(0, mseq);
}
wsinfo.setProgressName("region "+jobs[j].jobnum,jobs[j].jobnum);
wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
j++;
}
start = contigs[contig+1] + contigs[contig + 2];
}
if (start 0) {
jobs[j].allowedServerExceptions--;
Cache.log.debug("Sleeping after a server exception.");
try {
Thread.sleep(5000);
}
catch (InterruptedException ex1) {
}
} else {
Cache.log.warn("Dropping job "+j+" "+jobs[j].jobId);
jobs[j].subjobComplete=true;
wsInfo.setStatus(jobs[j].jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
}
}
catch (OutOfMemoryError er) {
jobComplete = true;
jobs[j].subjobComplete=true;
jobs[j].result=null; // may contain out of date result object
wsInfo.setStatus(jobs[j].jobnum,
WebserviceInfo.STATE_STOPPED_ERROR);
JOptionPane
.showInternalMessageDialog(
Desktop.desktop,
"Out of memory handling result for job !!"
+ "\nSee help files for increasing Java Virtual Machine memory.",
"Out of memory", JOptionPane.WARNING_MESSAGE);
Cache.log.error("Out of memory when retrieving Job "+j+" id:" + WsUrl+"/"+jobs[j].jobId, er);
System.gc();
}
}
if (jobs[j].result!=null) {
String progheader="";
// Parse state of job[j]
if (jobs[j].result.isRunning()) {
running++;
wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_RUNNING);
} else if (jobs[j].result.isQueued()) {
queuing++;
wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_QUEUING);
} else if (jobs[j].result.isFinished()) {
finished++;
jobs[j].subjobComplete = true;
wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_OK);
} else if (jobs[j].result.isFailed()) {
progheader += "Job failed.\n";
jobs[j].subjobComplete=true;
wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR);
error++;
} else if (jobs[j].result.isServerError()) {
serror++;
jobs[j].subjobComplete = true;
wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_SERVERERROR);
} else if (jobs[j].result.isBroken() || jobs[j].result.isFailed()) {
error++;
jobs[j].subjobComplete=true;
wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR);
}
// and pass on any sub-job messages to the user
wsInfo.setProgressText(jobs[j].jobnum, OutputHeader);
wsInfo.appendProgressText(jobs[j].jobnum, progheader);
if (jobs[j].result.getStatus() != null) {
wsInfo.appendProgressText(jobs[j].jobnum, jobs[j].result.getStatus());
}
} else {
if (jobs[j].submitted && jobs[j].subjobComplete) {
if (jobs[j].allowedServerExceptions==0) {
serror++;
} else if (jobs[j].result==null) {
error++;
}
}
}
}
// Decide on overall state based on collected jobs[] states
if (running>0) {
wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);
} else if (queuing>0) {
wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);
} else {
jobComplete=true;
if (finished>0) {
wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);
} else if (error>0) {
wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
} else if (serror>0) {
wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
}
}
if (!jobComplete) {
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
Cache.log.debug("Interrupted sleep waiting for next job poll.",e);
}
// System.out.println("I'm alive "+alTitle);
}
}
if (jobComplete) {
parseResult(); // tidy up and make results available to user
}
}
void StartJob(MsaWSJob j) {
if (j.submitted) {
if (Cache.log.isDebugEnabled()) {
Cache.log.debug("Tried to submit an already submitted job "+j.jobId);
}
return;
}
if (j.seqs.getSeqs()==null) {
// special case - selection consisted entirely of empty sequences...
j.submitted=true;
j.result=new MsaResult();
j.result.setFinished(true);
j.result.setStatus("Empty Alignment Job");
j.result.setMsa(null);
}
try {
vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
if ((jobsubmit != null) && (jobsubmit.getStatus() == 1)) {
j.jobId = jobsubmit.getJobId();
j.submitted=true;
j.subjobComplete = false;
// System.out.println(WsURL + " Job Id '" + jobId + "'");
} else {
if (jobsubmit == null) {
throw new Exception(
"Server at "
+ WsUrl
+ " returned null object, it probably cannot be contacted. Try again later ?");
}
throw new Exception(jobsubmit.getJobId());
}
} catch (Exception e) {
// TODO: JBPNote catch timeout or other fault types explicitly
// For unexpected errors
System.err
.println(WebServiceName
+ "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
+ "When contacting Server:" + WsUrl + "\n"
+ e.toString() + "\n");
j.allowedServerExceptions = 0;
wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
wsInfo
.appendProgressText(
j.jobnum,
"Failed to submit sequences for alignment.\n"
+ "It is most likely that there is a problem with the server.\n"
+ "Just close the window\n");
// e.printStackTrace(); // TODO: JBPNote DEBUG
}
}
private jalview.datamodel.Sequence[] getVamsasAlignment(
vamsas.objects.simple.Alignment valign) {
vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
for (int i = 0, j = seqs.length; i < j; i++) {
msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
.getSeq());
}
return msa;
}
void parseResult() {
try {
for (int j=0; j 0) {
int cshift=0;
int start = 0;
int nwidth = 0;
int j=0;
for (int contig = 0; contig < contigs.length; contig += 3) {
if (cshift+contigs[contig] - start > 0) {
Object[] subalg = jobs[j++].getAlignment();
alorders.add(subalg[1]);
SequenceI mseq[] = (SequenceI[]) subalg[0];
int width = mseq[0].getLength();
for (int s = 0; s < mseq.length; s++) {
if (alignment[s]==null) {
alignment[s] = mseq[s];
} else {
alignment[s].setSequence(alignment[s].getSequence()+mseq[s].getSequence());
if (mseq[s].getStart()<=mseq[s].getEnd())
alignment[s].setEnd(mseq[s].getEnd());
((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
}
}
nwidth+=width;
}
// advance to begining of visible region
start = cshift+contigs[contig] + contigs[contig + 2];
// add hidden segment to right of next region
for (int s=0; s=hseq.getStart())
alignment[s].setEnd(hseq.getEnd());
}
}
// mark hidden segment as hidden in the new alignment
columnselection.hideColumns(nwidth, nwidth+contigs[contig+2]-1);
nwidth+=contigs[contig+2];
cshift+=contigs[contig+2];
}
// Do final job - if it exists
if (j=mseq[s].getStart())
alignment[s].setEnd(mseq[s].getEnd());
((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
}
}
nwidth+=width;
}
} else {
if (jobs[0].hasResults()) {
Object[] alg = jobs[0].getAlignment();
alignment = (SequenceI[]) alg[0];
alorders.add(alg[1]);
} else {
alignment = SeqCigar.createAlignmentSequences(seqs, '-', columnselection,null);
}
}
Alignment al = new Alignment(alignment);
if (dataset != null) {
al.setDataset(dataset);
}
if (newFrame) {
// TODO: JBPNote Should also rename the query sequence
// sometime...
AlignFrame af = new AlignFrame(al,columnselection);
// >>>This is a fix for the moment, until a better solution is
// found!!<<<
af.getFeatureRenderer().transferSettings(
alignFrame.getFeatureRenderer());
if (alorders.size()>0) {
if (alorders.size()==1) {
af.addSortByOrderMenuItem(WebServiceName + " Ordering",
(AlignmentOrder) alorders.get(0));
} else {
// construct a non-redundant ordering set
Vector names=new Vector();
for (int i=0,l=alorders.size(); i