X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fws%2Fjws2%2FMsaWSThread.java;h=ee0fbc57c6dda1e2e70f793c69b426409ad26598;hb=cb8e52fbbc5f725e3f7f48c672cdddb0690bd978;hp=d9f92f99ba73aadd81542f397000965942cc3ca2;hpb=90a1b20c1297ec0d7fc596f89f6323a4b1bc7083;p=jalview.git diff --git a/src/jalview/ws/jws2/MsaWSThread.java b/src/jalview/ws/jws2/MsaWSThread.java index d9f92f9..ee0fbc5 100644 --- a/src/jalview/ws/jws2/MsaWSThread.java +++ b/src/jalview/ws/jws2/MsaWSThread.java @@ -1,60 +1,59 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5) - * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with Jalview. If not, see . + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.ws.jws2; -import java.util.*; +import jalview.analysis.AlignSeq; +import jalview.bin.Console; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentOrder; +import jalview.datamodel.AlignmentView; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.Desktop; +import jalview.gui.SplitFrame; +import jalview.gui.WebserviceInfo; +import jalview.util.MessageManager; +import jalview.ws.AWsJob; +import jalview.ws.JobStateSummary; +import jalview.ws.WSClientI; +import jalview.ws.jws2.dm.JabaWsParamSet; +import jalview.ws.params.WsParamSetI; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import javax.swing.JInternalFrame; import compbio.data.msa.MsaWS; -import compbio.data.sequence.AlignmentMetadata; -import compbio.data.sequence.Program; import compbio.metadata.Argument; import compbio.metadata.ChunkHolder; import compbio.metadata.JobStatus; import compbio.metadata.Preset; -import jalview.analysis.*; -import jalview.bin.*; -import jalview.datamodel.*; -import jalview.gui.*; -import jalview.ws.AWsJob; -import jalview.ws.WSClientI; -import jalview.ws.JobStateSummary; - -/** - *

- * Title: - *

- * - *

- * Description: - *

- * - *

- * Copyright: Copyright (c) 2004 - *

- * - *

- * Company: Dundee University - *

- * - * @author not attributable - * @version 1.0 - */ class MsaWSThread extends AWS2Thread implements WSClientI { boolean submitGaps = false; // pass sequences including gaps to alignment @@ -67,20 +66,26 @@ class MsaWSThread extends AWS2Thread implements WSClientI class MsaWSJob extends JWs2Job { - long lastChunk=0; - Preset preset=null; - List arguments = null; + long lastChunk = 0; + + WsParamSetI preset = null; + + List arguments = null; + /** - * input + * input */ ArrayList seqs = new ArrayList(); + /** * output */ compbio.data.sequence.Alignment alignment; - // set if the job didn't get run - then the input is simply returned to the user - private boolean returnInput=false; - + + // set if the job didn't get run - then the input is simply returned to the + // user + private boolean returnInput = false; + /** * MsaWSJob * @@ -101,7 +106,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI } - Hashtable SeqNames = new Hashtable(); + Hashtable SeqNames = new Hashtable(); Vector emptySeqs = new Vector(); @@ -120,8 +125,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI int nseqs = 0; if (minlen < 0) { - throw new Error( - "Implementation error: minlen must be zero or more."); + throw new Error(MessageManager.getString( + "error.implementation_error_minlen_must_be_greater_zero")); } for (int i = 0; i < seqs.length; i++) { @@ -139,15 +144,16 @@ class MsaWSThread extends AWS2Thread implements WSClientI // for // any // subjob - SeqNames.put(newname, jalview.analysis.SeqsetUtils - .SeqCharacterHash(seqs[i])); + SeqNames.put(newname, + jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i])); if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1) { // make new input sequence with or without gaps seq = new compbio.data.sequence.FastaSequence(newname, (submitGaps) ? seqs[i].getSequenceAsString() - : AlignSeq.extractGaps(jalview.util.Comparison.GapChars, - seqs[i].getSequenceAsString())); + : AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, + seqs[i].getSequenceAsString())); this.seqs.add(seq); } else @@ -155,12 +161,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI String empty = null; if (seqs[i].getEnd() >= seqs[i].getStart()) { - empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq - .extractGaps(jalview.util.Comparison.GapChars, seqs[i] - .getSequenceAsString()); + empty = (submitGaps) ? seqs[i].getSequenceAsString() + : AlignSeq.extractGaps(jalview.util.Comparison.GapChars, + seqs[i].getSequenceAsString()); } - emptySeqs.add(new String[] - { newname, empty }); + emptySeqs.add(new String[] { newname, empty }); } } return valid; @@ -170,9 +175,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI * * @return true if getAlignment will return a valid alignment result. */ + @Override public boolean hasResults() { - if (subjobComplete && isFinished() && (alignment!=null || (emptySeqs!=null && emptySeqs.size()>0))) + if (subjobComplete && isFinished() && (alignment != null + || (emptySeqs != null && emptySeqs.size() > 0))) { return true; } @@ -181,7 +188,10 @@ class MsaWSThread extends AWS2Thread implements WSClientI /** * - * get the alignment including any empty sequences in the original order with original ids. Caller must access the alignment.getMetadata() object to annotate the final result passsed to the user. + * get the alignment including any empty sequences in the original order + * with original ids. Caller must access the alignment.getMetadata() object + * to annotate the final result passsed to the user. + * * @return { SequenceI[], AlignmentOrder } */ public Object[] getAlignment() @@ -192,15 +202,17 @@ class MsaWSThread extends AWS2Thread implements WSClientI SequenceI[] alseqs = null; char alseq_gapchar = '-'; int alseq_l = 0; - if (alignment.getSequences().size()>0) + if (alignment.getSequences().size() > 0) { alseqs = new SequenceI[alignment.getSequences().size()]; - for (compbio.data.sequence.FastaSequence seq: alignment.getSequences()) + for (compbio.data.sequence.FastaSequence seq : alignment + .getSequences()) { - alseqs[alseq_l++] = new Sequence(seq.getId(),seq.getSequence()); + alseqs[alseq_l++] = new Sequence(seq.getId(), + seq.getSequence()); } alseq_gapchar = alignment.getMetadata().getGapchar(); - + } // add in the empty seqs. if (emptySeqs.size() > 0) @@ -224,7 +236,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI int ow = w, nw = w; for (i = 0, w = emptySeqs.size(); i < w; i++) { - String[] es = (String[]) emptySeqs.get(i); + String[] es = emptySeqs.get(i); if (es != null && es[1] != null) { int sw = es[1].length(); @@ -255,7 +267,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI } for (i = 0, w = emptySeqs.size(); i < w; i++) { - String[] es = (String[]) emptySeqs.get(i); + String[] es = emptySeqs.get(i); if (es[1] == null) { t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0], @@ -284,8 +296,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI jalview.analysis.AlignmentSorter.recoverOrder(alseqs); // account for any missing sequences jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs); - return new Object[] - { alseqs, msaorder }; + return new Object[] { alseqs, msaorder }; } return null; } @@ -304,16 +315,20 @@ class MsaWSThread extends AWS2Thread implements WSClientI * * @return boolean true if job can be submitted. */ + @Override public boolean hasValidInput() { - // TODO: get attributes for this MsaWS instance to check if it can do two sequence alignment. - if (seqs != null && seqs.size()>=2) // two or more sequences is valid ? + // TODO: get attributes for this MsaWS instance to check if it can do two + // sequence alignment. + if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ? { return true; } return false; } - StringBuffer jobProgress=new StringBuffer(); + + StringBuffer jobProgress = new StringBuffer(); + public void setStatus(String string) { jobProgress.setLength(0); @@ -329,7 +344,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI @Override public boolean hasStatus() { - return jobProgress!=null; + return jobProgress != null; } /** @@ -341,24 +356,87 @@ class MsaWSThread extends AWS2Thread implements WSClientI } /** - * @param lastChunk the lastChunk to set + * @param lastChunk + * the lastChunk to set */ public void setLastChunk(long lastChunk) { this.lastChunk = lastChunk; } - String alignmentProgram=null; + String alignmentProgram = null; + public String getAlignmentProgram() { return alignmentProgram; } - + + public boolean hasArguments() + { + return (arguments != null && arguments.size() > 0) + || (preset != null && preset instanceof JabaWsParamSet); + } + + public List getJabaArguments() + { + List newargs = new ArrayList(); + if (preset != null && preset instanceof JabaWsParamSet) + { + newargs.addAll(((JabaWsParamSet) preset).getjabaArguments()); + } + if (arguments != null && arguments.size() > 0) + { + newargs.addAll(arguments); + } + return newargs; + } + + /** + * add a progess header to status string containing presets/args used + */ + public void addInitialStatus() + { + if (preset != null) + { + jobProgress.append("Using " + + (preset instanceof JabaPreset ? "Server" : "User") + + "Preset: " + preset.getName()); + if (preset instanceof JabaWsParamSet) + { + for (Argument opt : ((JabaWsParamSet) preset).getjabaArguments()) + { + jobProgress.append( + opt.getName() + " " + opt.getDefaultValue() + "\n"); + } + } + } + if (arguments != null && arguments.size() > 0) + { + jobProgress.append("With custom parameters : \n"); + // merge arguments with preset's own arguments. + for (Argument opt : arguments) + { + jobProgress.append( + opt.getName() + " " + opt.getDefaultValue() + "\n"); + } + } + jobProgress.append("\nJob Output:\n"); + } + + public boolean isPresetJob() + { + return preset != null && preset instanceof JabaPreset; + } + + public Preset getServerPreset() + { + return (isPresetJob()) ? ((JabaPreset) preset).p : null; + } } String alTitle; // name which will be used to form new alignment window. - Alignment dataset; // dataset to which the new alignment will be + AlignmentI dataset; // dataset to which the new alignment will be // associated. @@ -373,10 +451,9 @@ class MsaWSThread extends AWS2Thread implements WSClientI * @param presorder * boolean */ - MsaWSThread(MsaWS server, String wsUrl, - WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, - AlignmentView alview, String wsname, boolean subgaps, - boolean presorder) + private MsaWSThread(MsaWS server, String wsUrl, WebserviceInfo wsinfo, + jalview.gui.AlignFrame alFrame, AlignmentView alview, + String wsname, boolean subgaps, boolean presorder) { super(alFrame, wsinfo, alview, wsname, wsUrl); this.server = server; @@ -398,12 +475,13 @@ class MsaWSThread extends AWS2Thread implements WSClientI * @param seqset * Alignment */ - MsaWSThread(MsaWS server2, Preset preset, List paramset, String wsUrl, - WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, - String wsname, String title, AlignmentView _msa, boolean subgaps, - boolean presorder, Alignment seqset) + MsaWSThread(MsaWS server2, WsParamSetI preset, List paramset, + String wsUrl, WebserviceInfo wsinfo, + jalview.gui.AlignFrame alFrame, String wsname, String title, + AlignmentView _msa, boolean subgaps, boolean presorder, + AlignmentI seqset) { - this(server2,wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder); + this(server2, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder); OutputHeader = wsInfo.getProgressText(); alTitle = title; dataset = seqset; @@ -411,7 +489,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI SequenceI[][] conmsa = _msa.getVisibleContigs('-'); if (conmsa != null) { - int njobs = conmsa.length; + int nvalid = 0, njobs = conmsa.length; jobs = new MsaWSJob[njobs]; for (int j = 0; j < njobs; j++) { @@ -423,25 +501,42 @@ class MsaWSThread extends AWS2Thread implements WSClientI { jobs[j] = new MsaWSJob(0, conmsa[j]); } + if (((MsaWSJob) jobs[j]).hasValidInput()) + { + nvalid++; + } ((MsaWSJob) jobs[j]).preset = preset; ((MsaWSJob) jobs[j]).arguments = paramset; ((MsaWSJob) jobs[j]).alignmentProgram = wsname; if (njobs > 0) { - wsinfo - .setProgressName("region " + jobs[j].getJobnum(), - jobs[j].getJobnum()); + wsinfo.setProgressName("region " + jobs[j].getJobnum(), + jobs[j].getJobnum()); } wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader); } + validInput = nvalid > 0; } } + boolean validInput = false; + + /** + * + * @return true if the thread will perform a calculation + */ + public boolean hasValidInput() + { + return validInput; + } + + @Override public boolean isCancellable() { return true; } + @Override public void cancelJob() { if (!jobComplete && jobs != null) @@ -454,17 +549,20 @@ class MsaWSThread extends AWS2Thread implements WSClientI String cancelledMessage = ""; try { - boolean cancelledJob = server - .cancelJob(jobs[job].getJobId()); - if (cancelledJob) + boolean cancelledJob = server.cancelJob(jobs[job].getJobId()); + if (true) // cancelledJob || true) { // CANCELLED_JOB + // if the Jaba server indicates the job can't be cancelled, its + // because its running on the server's local execution engine + // so we just close the window anyway. cancelledMessage = "Job cancelled."; - ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this ugliness - + ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this + // ugliness - wsInfo.setStatus(jobs[job].getJobnum(), WebserviceInfo.STATE_CANCELLED_OK); - } - else + } + else { // VALID UNSTOPPABLE JOB cancelledMessage += "Server cannot cancel this job. just close the window.\n"; @@ -476,11 +574,20 @@ class MsaWSThread extends AWS2Thread implements WSClientI { cancelledMessage += ("\nProblems cancelling the job : Exception received...\n" + exc + "\n"); - Cache.log.warn( - "Exception whilst cancelling " + jobs[job].getJobId(), exc); + Console.warn( + "Exception whilst cancelling " + jobs[job].getJobId(), + exc); } - wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader - + cancelledMessage + "\n"); + wsInfo.setProgressText(jobs[job].getJobnum(), + OutputHeader + cancelledMessage + "\n"); + } + else + { + // if we hadn't submitted then just mark the job as cancelled. + jobs[job].setSubjobComplete(true); + wsInfo.setStatus(jobs[job].getJobnum(), + WebserviceInfo.STATE_CANCELLED_OK); + } } if (cancelled) @@ -494,119 +601,192 @@ class MsaWSThread extends AWS2Thread implements WSClientI { if (!jobComplete) { - wsInfo - .setProgressText(OutputHeader - + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n"); + wsInfo.setProgressText(OutputHeader + + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n"); } } } + @Override public void pollJob(AWsJob job) throws Exception { // TODO: investigate if we still need to cast here in J1.6 - MsaWSJob j=((MsaWSJob) job); - // this is standard code, but since the interface doesn't comprise of a basic one that implements (getJobStatus, pullExecStatistics) we have to repeat the code for all jw2s services. + MsaWSJob j = ((MsaWSJob) job); + // this is standard code, but since the interface doesn't comprise of a + // basic one that implements (getJobStatus, pullExecStatistics) we have to + // repeat the code for all jw2s services. j.setjobStatus(server.getJobStatus(job.getJobId())); updateJobProgress(j); } - protected void updateJobProgress(MsaWSJob j) throws Exception { + + /** + * + * @param j + * @return true if more job progress data was available + * @throws Exception + */ + protected boolean updateJobProgress(MsaWSJob j) throws Exception + { StringBuffer response = j.jobProgress; long lastchunk = j.getLastChunk(); - do { + boolean changed = false; + do + { j.setLastChunk(lastchunk); - ChunkHolder chunk = server.pullExecStatistics(j.getJobId(), lastchunk); - if (chunk!=null) { + ChunkHolder chunk = server.pullExecStatistics(j.getJobId(), + lastchunk); + if (chunk != null) + { + changed |= chunk.getChunk().length() > 0; response.append(chunk.getChunk()); lastchunk = chunk.getNextPosition(); - }; - } while (lastchunk>=0 && j.getLastChunk()!=lastchunk); + try + { + Thread.sleep(50); + } catch (InterruptedException x) + { + } + ; + } + ; + } while (lastchunk >= 0 && j.getLastChunk() != lastchunk); + return changed; } + @Override public void StartJob(AWsJob job) { + Exception lex = null; // boiler plate template if (!(job instanceof MsaWSJob)) { - throw new Error("StartJob(MsaWSJob) called on a WSJobInstance " - + job.getClass()); + throw new Error(MessageManager.formatMessage( + "error.implementation_error_msawbjob_called", new String[] + { job.getClass().toString() })); } MsaWSJob j = (MsaWSJob) job; if (j.isSubmitted()) { - if (Cache.log.isDebugEnabled()) + if (Console.isDebugEnabled()) { - Cache.log.debug("Tried to submit an already submitted job " - + j.getJobId()); + Console.debug( + "Tried to submit an already submitted job " + j.getJobId()); } return; } // end boilerplate - - if (j.seqs == null || j.seqs.size()==0) + + if (j.seqs == null || j.seqs.size() == 0) { // special case - selection consisted entirely of empty sequences... j.setjobStatus(JobStatus.FINISHED); - j.setStatus("Empty Alignment Job"); + j.setStatus(MessageManager.getString("label.empty_alignment_job")); } try { - // TODO: get the parameters (if any) for this job and submit the job - if (j.arguments!=null && j.arguments.size()>0) + j.addInitialStatus(); // list the presets/parameters used for the job in + // status + if (j.isPresetJob()) { - StringBuffer pset = new StringBuffer(); - for (Argument arg: j.arguments) { - pset.append(arg.getName()+" "+arg.getDefaultValue()+"\n"); - } - j.setStatus("Custom Parameters:\n"+pset.toString()+"\nJob Output:\n"); - j.setJobId(server.customAlign(j.seqs, j.arguments)); - } else - if (j.preset!=null) - { - j.setJobId(server.presetAlign(j.seqs, j.preset)); - } else { - j.setJobId(server.align(j.seqs)); - } + j.setJobId(server.presetAlign(j.seqs, j.getServerPreset())); + } + else if (j.hasArguments()) + { + j.setJobId(server.customAlign(j.seqs, j.getJabaArguments())); + } + else + { + j.setJobId(server.align(j.seqs)); + } - if (j.getJobId()!= null) + if (j.getJobId() != null) { j.setSubmitted(true); j.setSubjobComplete(false); // System.out.println(WsURL + " Job Id '" + jobId + "'"); + return; } else { - throw new Exception( - "Server at " - + WsUrl - + " returned null string for job id, it probably cannot be contacted. Try again later ?"); - } + throw new Exception(MessageManager.formatMessage( + "exception.web_service_returned_null_try_later", + new String[] + { WsUrl })); + } + } catch (compbio.metadata.UnsupportedRuntimeException _lex) + { + lex = _lex; + wsInfo.appendProgressText(MessageManager.formatMessage( + "info.job_couldnt_be_run_server_doesnt_support_program", + new String[] + { _lex.getMessage() })); + wsInfo.warnUser(_lex.getMessage(), + MessageManager.getString("warn.service_not_supported")); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); + wsInfo.setStatus(j.getJobnum(), + WebserviceInfo.STATE_STOPPED_SERVERERROR); + } catch (compbio.metadata.LimitExceededException _lex) + { + lex = _lex; + wsInfo.appendProgressText(MessageManager.formatMessage( + "info.job_couldnt_be_run_exceeded_hard_limit", new String[] + { _lex.getMessage() })); + wsInfo.warnUser(_lex.getMessage(), + MessageManager.getString("warn.input_is_too_big")); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR); + } catch (compbio.metadata.WrongParameterException _lex) + { + lex = _lex; + wsInfo.warnUser(_lex.getMessage(), + MessageManager.getString("warn.invalid_job_param_set")); + wsInfo.appendProgressText(MessageManager.formatMessage( + "info.job_couldnt_be_run_incorrect_param_setting", + new String[] + { _lex.getMessage() })); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR); + } catch (Error e) + { + // 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.printStackTrace(System.err); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); + wsInfo.setStatus(j.getJobnum(), + WebserviceInfo.STATE_STOPPED_SERVERERROR); } catch (Exception e) { - // Boilerplate code here - // 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"); + System.err.println(WebServiceName + + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n" + + "When contacting Server:" + WsUrl + "\n"); e.printStackTrace(System.err); - j.setAllowedServerExceptions(0); wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); - wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_SERVERERROR); - wsInfo - .appendProgressText( - j.getJobnum(), - "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"); + wsInfo.setStatus(j.getJobnum(), + WebserviceInfo.STATE_STOPPED_SERVERERROR); + } finally + { + if (!j.isSubmitted()) + { + // Boilerplate code here + // TODO: JBPNote catch timeout or other fault types explicitly - // e.printStackTrace(); // TODO: JBPNote DEBUG + j.setAllowedServerExceptions(0); + wsInfo.appendProgressText(j.getJobnum(), MessageManager.getString( + "info.failed_to_submit_sequences_for_alignment")); + } } } - + @Override public void parseResult() { + long progbar = System.currentTimeMillis(); + wsInfo.setProgressBar( + MessageManager.getString("status.collecting_job_results"), + progbar); int results = 0; // number of result sets received JobStateSummary finalState = new JobStateSummary(); try @@ -614,28 +794,74 @@ class MsaWSThread extends AWS2Thread implements WSClientI for (int j = 0; j < jobs.length; j++) { MsaWSJob msjob = ((MsaWSJob) jobs[j]); - if (jobs[j].isFinished() && msjob.alignment==null) + if (jobs[j].isFinished() && msjob.alignment == null) { - try { - updateJobProgress(msjob); - } catch (Exception e) + int nunchanged = 3, nexcept = 3; + boolean jpchanged = false, jpex = false; + do { - Cache.log.warn("Exception when retrieving remaining Job progress data for job "+msjob.getJobId()+" on server "+WsUrl); - e.printStackTrace(); - } - if (Cache.log.isDebugEnabled()) + try + { + jpchanged = updateJobProgress(msjob); + jpex = false; + if (jpchanged) + { + nexcept = 3; + } + } catch (Exception e) + { + + Console.warn( + "Exception when retrieving remaining Job progress data for job " + + msjob.getJobId() + " on server " + WsUrl); + e.printStackTrace(); + nexcept--; + nunchanged = 3; + // set flag remember that we've had an exception. + jpex = true; + jpchanged = false; + } + if (!jpchanged) + { + try + { + Thread.sleep(jpex ? 2400 : 1200); // wait a bit longer if we + // experienced an exception. + } catch (Exception ex) + { + } + ; + nunchanged--; + } + } while (nunchanged > 0 && nexcept > 0); + + if (Console.isDebugEnabled()) { - System.out.println("Job Execution file for job: "+msjob.getJobId()+" on server "+WsUrl); + System.out.println("Job Execution file for job: " + + msjob.getJobId() + " on server " + WsUrl); System.out.println(msjob.getStatus()); System.out.println("*** End of status"); - + } - try { + try + { msjob.alignment = server.getResult(msjob.getJobId()); - } - catch (Exception e) + } catch (compbio.metadata.ResultNotAvailableException e) + { + // job has failed for some reason - probably due to invalid + // parameters + Console.debug( + "Results not available for finished job - marking as broken job.", + e); + msjob.jobProgress.append( + "\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n" + + e.getLocalizedMessage()); + msjob.setjobStatus(JobStatus.FAILED); + } catch (Exception e) { - Cache.log.error("Couldn't get Alignment for job.",e); + Console.error("Couldn't get Alignment for job.", e); + // TODO: Increment count and retry ? + msjob.setjobStatus(JobStatus.UNDEFINED); } } finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]); @@ -646,9 +872,12 @@ class MsaWSThread extends AWS2Thread implements WSClientI compbio.data.sequence.Alignment alignment = ((MsaWSJob) jobs[j]).alignment; if (alignment != null) { - wsInfo.appendProgressText(jobs[j].getJobnum(), - "\nAlignment Object Method Notes\n"); - wsInfo.appendProgressText(jobs[j].getJobnum(), "Calculated with "+alignment.getMetadata().getProgram().toString()); + // server.close(jobs[j].getJobnum()); + // wsInfo.appendProgressText(jobs[j].getJobnum(), + // "\nAlignment Object Method Notes\n"); + // wsInfo.appendProgressText(jobs[j].getJobnum(), + // "Calculated with + // "+alignment.getMetadata().getProgram().toString()); // JBPNote The returned files from a webservice could be // hidden behind icons in the monitor window that, // when clicked, pop up their corresponding data @@ -658,8 +887,9 @@ class MsaWSThread extends AWS2Thread implements WSClientI } catch (Exception ex) { - Cache.log.error("Unexpected exception when processing results for " - + alTitle, ex); + Console.error( + "Unexpected exception when processing results for " + alTitle, + ex); wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); } if (results > 0) @@ -667,6 +897,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI wsInfo.showResultsNewFrame .addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent evt) { displayResults(true); @@ -675,6 +906,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI wsInfo.mergeResults .addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent evt) { displayResults(false); @@ -686,12 +918,20 @@ class MsaWSThread extends AWS2Thread implements WSClientI { wsInfo.setFinishedNoResults(); } + updateGlobalStatus(finalState); + wsInfo.setProgressBar(null, progbar); } + /** + * Display alignment results in a new frame (or - not currently supported - + * added to an existing alignment). + * + * @param newFrame + */ void displayResults(boolean newFrame) { // view input or result data for each block - Vector alorders = new Vector(); + List alorders = new ArrayList(); SequenceI[][] results = new SequenceI[jobs.length][]; AlignmentOrder[] orders = new AlignmentOrder[jobs.length]; String lastProgram = null; @@ -700,10 +940,10 @@ class MsaWSThread extends AWS2Thread implements WSClientI { if (jobs[j].hasResults()) { - msjob = (MsaWSJob)jobs[j]; + msjob = (MsaWSJob) jobs[j]; Object[] res = msjob.getAlignment(); lastProgram = msjob.getAlignmentProgram(); - alorders.add(res[1]); + alorders.add((AlignmentOrder) res[1]); results[j] = (SequenceI[]) res[0]; orders[j] = (AlignmentOrder) res[1]; @@ -722,10 +962,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI orders[j] = null; } SequenceI[] alignment = (SequenceI[]) newview[0]; - ColumnSelection columnselection = (ColumnSelection) newview[1]; + HiddenColumns hidden = (HiddenColumns) newview[1]; Alignment al = new Alignment(alignment); // TODO: add 'provenance' property to alignment from the method notes - if (lastProgram!=null) { + if (lastProgram != null) + { al.setProperty("Alignment Program", lastProgram); } // accompanying each subjob @@ -739,74 +980,142 @@ class MsaWSThread extends AWS2Thread implements WSClientI if (newFrame) { - AlignFrame af = new AlignFrame(al, columnselection, - AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + displayInNewFrame(al, alorders, hidden); - // initialise with same renderer settings as in parent alignframe. - af.getFeatureRenderer().transferSettings(this.featureSettings); - // update orders - 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 < l; i++) - { - String orderName = new String(" Region " + i); - int j = i + 1; + } + else + { + // TODO 2.9.x feature + System.out.println("MERGE WITH OLD FRAME"); + // TODO: modify alignment in original frame, replacing old for new + // alignment using the commands.EditCommand model to ensure the update can + // be undone + } + } - while (j < l) - { - if (((AlignmentOrder) alorders.get(i)) - .equals(((AlignmentOrder) alorders.get(j)))) - { - alorders.remove(j); - l--; - orderName += "," + j; - } - else - { - j++; - } - } + /** + * Display the alignment result in a new frame. + * + * @param al + * @param alorders + * @param columnselection + */ + protected void displayInNewFrame(AlignmentI al, + List alorders, HiddenColumns hidden) + { + AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); - if (i == 0 && j == 1) - { - names.add(new String("")); - } - else - { - names.add(orderName); - } - } - for (int i = 0, l = alorders.size(); i < l; i++) - { - af.addSortByOrderMenuItem(WebServiceName - + ((String) names.get(i)) + " Ordering", - (AlignmentOrder) alorders.get(i)); - } - } + // initialise with same renderer settings as in parent alignframe. + af.getFeatureRenderer().transferSettings(this.featureSettings); + + if (alorders.size() > 0) + { + addSortByMenuItems(af, alorders); + } + + // TODO: refactor retrieve and show as new splitFrame as Desktop method + + /* + * If alignment was requested from one half of a SplitFrame, show in a + * SplitFrame with the other pane similarly aligned. + */ + AlignFrame requestedBy = getRequestingAlignFrame(); + if (requestedBy != null && requestedBy.getSplitViewContainer() != null + && requestedBy.getSplitViewContainer() + .getComplement(requestedBy) != null) + { + AlignmentI complement = requestedBy.getSplitViewContainer() + .getComplement(requestedBy); + String complementTitle = requestedBy.getSplitViewContainer() + .getComplementTitle(requestedBy); + // becomes null if the alignment window was closed before the alignment + // job finished. + AlignmentI copyComplement = new Alignment(complement); + // todo should this be done by copy constructor? + copyComplement.setGapCharacter(complement.getGapCharacter()); + // share the same dataset (and the mappings it holds) + copyComplement.setDataset(complement.getDataset()); + copyComplement.alignAs(al); + if (copyComplement.getHeight() > 0) + { + af.setTitle(alTitle); + AlignFrame af2 = new AlignFrame(copyComplement, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + af2.setTitle(complementTitle); + String linkedTitle = MessageManager + .getString("label.linked_view_title"); + JInternalFrame splitFrame = new SplitFrame( + al.isNucleotide() ? af : af2, al.isNucleotide() ? af2 : af); + Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1); + return; } + } - Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH, - AlignFrame.DEFAULT_HEIGHT); + /* + * Not from SplitFrame, or failed to created a complementary alignment + */ + Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); + } + /** + * Add sort order options to the AlignFrame menus. + * + * @param af + * @param alorders + */ + protected void addSortByMenuItems(AlignFrame af, + List alorders) + { + // update orders + if (alorders.size() == 1) + { + af.addSortByOrderMenuItem(WebServiceName + " Ordering", + alorders.get(0)); } else { - System.out.println("MERGE WITH OLD FRAME"); - // TODO: modify alignment in original frame, replacing old for new - // alignment using the commands.EditCommand model to ensure the update can - // be undone + // construct a non-redundant ordering set + List names = new ArrayList(); + for (int i = 0, l = alorders.size(); i < l; i++) + { + String orderName = " Region " + i; + int j = i + 1; + + while (j < l) + { + if (alorders.get(i).equals(alorders.get(j))) + { + alorders.remove(j); + l--; + orderName += "," + j; + } + else + { + j++; + } + } + + if (i == 0 && j == 1) + { + names.add(""); + } + else + { + names.add(orderName); + } + } + for (int i = 0, l = alorders.size(); i < l; i++) + { + af.addSortByOrderMenuItem( + WebServiceName + (names.get(i)) + " Ordering", + alorders.get(i)); + } } } + @Override public boolean canMergeResults() { return false;