/* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package jalview.ws; import java.util.*; import javax.swing.*; import ext.vamsas.*; import jalview.analysis.*; import jalview.bin.*; import jalview.datamodel.*; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentView; import jalview.gui.*; import jalview.io.*; import jalview.util.*; import jalview.ws.WSThread.*; import vamsas.objects.simple.*; public class JPredClient extends WSClient { /** * crate a new GUI JPred Job * @param sh ServiceHandle * @param title String * @param msa boolean - true - submit alignment as a sequence profile * @param alview AlignmentView */ public JPredClient(ext.vamsas.ServiceHandle sh, String title, boolean msa, AlignmentView alview, AlignFrame parentFrame) { super(); wsInfo=setWebService(sh); startJPredClient(title, msa, alview, parentFrame); } /** * startJPredClient * TODO: refine submission to cope with local prediction of visible regions or multiple single sequence jobs * TODO: sequence representative support - could submit alignment of representatives as msa. * TODO: msa hidden region prediction - submit each chunk for prediction. concatenate results of each. * TODO: single seq prediction - submit each contig of each sequence for prediction (but must cope with flanking regions and short seqs) * @param title String * @param msa boolean * @param alview AlignmentView */ private void startJPredClient(String title, boolean msa, jalview.datamodel.AlignmentView alview, AlignFrame parentFrame) { AlignmentView input = alview; if (wsInfo == null) { wsInfo = setWebService(); } Jpred server = locateWebService(); if (server == null) { Cache.log.warn("Couldn't find a Jpred webservice to invoke!"); return; } SeqCigar[] msf = input.getSequences(); SequenceI seq = msf[0].getSeq('-'); if (msa && msf.length > 1) { String altitle = "JNet prediction on " + seq.getName() + " using alignment from " + title; wsInfo.setProgressText("Job details for MSA based prediction (" + title + ") on sequence :\n>" + seq.getName() + "\n" + AlignSeq.extractGaps("-. ", seq.getSequence()) + "\n"); SequenceI aln[] = new SequenceI[msf.length]; for (int i = 0, j = msf.length; i < j; i++) { aln[i] = msf[i].getSeq('-'); } Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true); JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, aln, alview, parentFrame); wsInfo.setthisService(jthread); jthread.start(); } else { if (!msa && msf.length>1) throw new Error("Implementation Error! Multiple single sequence prediction jobs are not yet supported."); wsInfo.setProgressText("Job details for prediction on sequence :\n>" + seq.getName() + "\n" + AlignSeq.extractGaps("-. ", seq.getSequence()) + "\n"); String altitle = "JNet prediction for sequence " + seq.getName() + " from " + title; Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash( seq); JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, seq, alview, parentFrame); wsInfo.setthisService(jthread); jthread.start(); } } public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI seq, AlignFrame parentFrame) { super(); wsInfo = setWebService(sh); startJPredClient(title, seq, parentFrame); } public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI[] msa, AlignFrame parentFrame) { wsInfo = setWebService(sh); startJPredClient(title, msa, parentFrame); } public JPredClient(String title, SequenceI[] msf) { startJPredClient(title, msf, null); } public JPredClient(String title, SequenceI seq) { startJPredClient(title, seq, null); } private void startJPredClient(String title, SequenceI[] msf, AlignFrame parentFrame) { if (wsInfo == null) { wsInfo = setWebService(); } SequenceI seq = msf[0]; String altitle = "JNet prediction on " + seq.getName() + " using alignment from " + title; wsInfo.setProgressText("Job details for MSA based prediction (" + title + ") on sequence :\n>" + seq.getName() + "\n" + AlignSeq.extractGaps("-. ", seq.getSequence()) + "\n"); SequenceI aln[] = new SequenceI[msf.length]; for (int i = 0, j = msf.length; i < j; i++) { aln[i] = new jalview.datamodel.Sequence(msf[i]); } Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true); Jpred server = locateWebService(); if (server==null) { return; } JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, aln,null, parentFrame); wsInfo.setthisService(jthread); jthread.start(); } public void startJPredClient(String title, SequenceI seq, AlignFrame parentFrame) { if (wsInfo == null) { wsInfo = setWebService(); } wsInfo.setProgressText("Job details for prediction on sequence :\n>" + seq.getName() + "\n" + AlignSeq.extractGaps("-. ", seq.getSequence()) + "\n"); String altitle = "JNet prediction for sequence " + seq.getName() + " from " + title; Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash(seq); Jpred server = locateWebService(); if (server==null) { return; } JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, seq,null, parentFrame); wsInfo.setthisService(jthread); jthread.start(); } private WebserviceInfo setWebService() { WebServiceName = "JNetWS"; WebServiceJobTitle = "JNet secondary structure prediction"; WebServiceReference = "\"Cuff J. A and Barton G.J (2000) Application of " + "multiple sequence alignment profiles to improve protein secondary structure prediction, " + "Proteins 40:502-511\"."; WsURL = "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred"; WebserviceInfo wsInfo = new WebserviceInfo(WebServiceJobTitle, WebServiceReference); return wsInfo; } private ext.vamsas.Jpred locateWebService() { ext.vamsas.JpredServiceLocator loc = new JpredServiceLocator(); // Default ext.vamsas.Jpred server=null; try { server = loc.getjpred(new java.net.URL(WsURL)); // JBPNote will be set from properties ( (JpredSoapBindingStub)server).setTimeout(60000); // one minute stub //((JpredSoapBindingStub)this.server)._setProperty(org.apache.axis.encoding.C, Boolean.TRUE); } catch (Exception ex) { JOptionPane.showMessageDialog(Desktop.desktop, "The Secondary Structure Prediction Service named " + WebServiceName + " at " + WsURL + " couldn't be located.", "Internal Jalview Error", JOptionPane.WARNING_MESSAGE); wsInfo.setProgressText("Serious! " + WebServiceName + " Service location failed\nfor URL :" + WsURL + "\n" + ex.getMessage()); wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); } return server; } class JPredThread extends WSThread implements WSClientI { class JPredJob extends WSThread.WSJob { vamsas.objects.simple.Sequence sequence; vamsas.objects.simple.Msfalignment msa; java.util.Hashtable SequenceInfo = null; /** * * @return true if getResultSet will return a valid alignment and prediction result. */ public boolean hasResults() { if (subjobComplete && result != null && result.isFinished() && ( (JpredResult) result).getPredfile() != null && ( (JpredResult) result).getAligfile() != null) { return true; } return false; } boolean hasValidInput() { if (sequence != null) { return true; } return false; } public Alignment getResultSet() throws Exception { if (result == null || !result.isFinished()) { return null; } Alignment al = null; int FirstSeq = -1; // the position of the query sequence in Alignment al JpredResult result = (JpredResult)this.result; jalview.bin.Cache.log.debug("Parsing output from JNet job."); // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File"); jalview.io.JPredFile prediction = new jalview.io.JPredFile(result. getPredfile(), "Paste"); SequenceI[] preds = prediction.getSeqsAsArray(); jalview.bin.Cache.log.debug("Got prediction profile."); if ( (this.msa != null) && (result.getAligfile() != null)) { jalview.bin.Cache.log.debug("Getting associated alignment."); // we ignore the returned alignment if we only predicted on a single sequence String format = new jalview.io.IdentifyFile().Identify(result. getAligfile(), "Paste"); if (jalview.io.FormatAdapter.isValidFormat(format)) { al = new Alignment(new FormatAdapter().readFile(result.getAligfile(), "Paste", format)); SequenceI sqs[] = new SequenceI[al.getHeight()]; for (int i = 0, j = al.getHeight(); i < j; i++) { sqs[i] = al.getSequenceAt(i); } if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable) SequenceInfo, sqs)) { throw (new Exception( "Couldn't recover sequence properties for alignment.")); } FirstSeq = 0; al.setDataset(null); jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq, false); } else { throw (new Exception( "Unknown format "+format+" for file : \n" + result.getAligfile())); } } else { al = new Alignment(preds); FirstSeq = prediction.getQuerySeqPosition(); if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash( al.getSequenceAt(FirstSeq), SequenceInfo)) { throw (new Exception( "Couldn't recover sequence properties for JNet Query sequence!")); } else { al.setDataset(null); jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq, true); } } return al; // , FirstSeq, noMsa}; } public JPredJob(Hashtable SequenceInfo, SequenceI seq) { super(); String sq = AlignSeq.extractGaps(Comparison.GapChars, seq.getSequence()); if (sq.length() >= 20) { this.SequenceInfo = SequenceInfo; sequence = new vamsas.objects.simple.Sequence(); sequence.setId(seq.getName()); sequence.setSeq(sq); } } public JPredJob(Hashtable SequenceInfo, SequenceI[] msf) { this(SequenceInfo, msf[0]); if (sequence != null) { if (msf.length > 1) { msa = new vamsas.objects.simple.Msfalignment(); jalview.io.PileUpfile pileup = new jalview.io.PileUpfile(); msa.setMsf(pileup.print(msf)); } } } } ext.vamsas.Jpred server; String altitle = ""; JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, AlignmentView alview, AlignFrame alframe) { this.altitle = altitle; this.server = server; this.wsInfo = wsinfo; this.input = alview; this.alignFrame = alframe; } // String OutputHeader; // vamsas.objects.simple.JpredResult result; JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo,SequenceI seq, AlignmentView alview, AlignFrame alframe) { this(wsinfo, altitle, server,alview, alframe); JPredJob job = new JPredJob(SequenceInfo, seq); if (job.hasValidInput()) { OutputHeader = wsInfo.getProgressText(); jobs = new WSJob[] { job}; job.jobnum = 0; } } JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo, SequenceI[] msf, AlignmentView alview, AlignFrame alframe) { this(wsinfo, altitle, server,alview, alframe); JPredJob job = new JPredJob(SequenceInfo, msf); if (job.hasValidInput()) { jobs = new WSJob[] { job}; OutputHeader = wsInfo.getProgressText(); job.jobnum = 0; } } /* public void run() { StartJob(); while (!jobComplete && (allowedServerExceptions > 0)) { try { if ( (result = server.getresult(jobId)) == null) { throw (new Exception( "Timed out when communicating with server\nTry again later.\n")); } if (result.getState()==0) jalview.bin.Cache.log.debug("Finished "+jobId); if (result.isRunning()) { wsInfo.setStatus(WebserviceInfo.STATE_RUNNING); } if (result.isQueued()) { wsInfo.setStatus(WebserviceInfo.STATE_QUEUING); } wsInfo.setProgressText(OutputHeader + "\n" + result.getStatus()); if (result.isFinished()) { parseResult(); jobComplete = true; jobsRunning--; } else { // catch exceptions if (! (result.isJobFailed() || result.isServerError())) { try { Thread.sleep(5000); } catch (InterruptedException ex1) { } // System.out.println("I'm alive "+seqid+" "+jobid); } else { wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); jobsRunning--; jobComplete = true; } } } catch (Exception ex) { allowedServerExceptions--; wsInfo.appendProgressText("\nJPredWS Server exception!\n" + ex.getMessage()); try { if (allowedServerExceptions > 0) { Thread.sleep(5000); } } catch (InterruptedException ex1) { } } catch (OutOfMemoryError er) { jobComplete = true; wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); JOptionPane.showInternalMessageDialog(Desktop.desktop, "Out of memory handling result!!" + "\nSee help files for increasing Java Virtual Machine memory." , "Out of memory", JOptionPane.WARNING_MESSAGE); System.out.println("JPredClient: "+er); System.gc(); } } if (result!=null) if (! (result.isJobFailed() || result.isServerError())) { wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK); } else { wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); } } */ void StartJob(WSJob j) { if (! (j instanceof JPredJob)) { throw new Error("Implementation error - StartJob(JpredJob) called on " + j.getClass()); } try { JPredJob job = (JPredJob) j; if (job.msa != null) { job.jobId = server.predictOnMsa(job.msa); } else if (job.sequence!=null) { job.jobId = server.predict(job.sequence); // debug like : job.jobId = "/jobs/www-jpred/jp_Yatat29";// } if (job.jobId != null) { if (job.jobId.startsWith("Broken")) { job.result = (vamsas.objects.simple.Result)new JpredResult(); job.result.setInvalid(true); job.result.setStatus("Submission " + job.jobId); } else { job.submitted = true; job.subjobComplete = false; Cache.log.info(WsURL + " Job Id '" + job.jobId + "'"); } } else { throw new Exception("Server timed out - try again later\n"); } } catch (Exception e) { if (e.getMessage().indexOf("Exception") > -1) { wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR); wsInfo.setProgressText(j.jobnum, "Failed to submit the prediction. (Just close the window)\n" + "It is most likely that there is a problem with the server.\n"); System.err.println( "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" + e.getMessage() + "\n"); jalview.bin.Cache.log.warn("Server Exception", e); } else { wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR); // JBPNote - this could be a popup informing the user of the problem. wsInfo.appendProgressText(j.jobnum, "Failed to submit the prediction:\n" + e.getMessage() + wsInfo.getProgressText()); jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e); } j.allowedServerExceptions = -1; j.subjobComplete = true; } } /* private void addFloatAnnotations(Alignment al, int[] gapmap, Vector values, String Symname, String Visname, float min, float max, int winLength) { Annotation[] annotations = new Annotation[al.getWidth()]; for (int j = 0; j < values.size(); j++) { float value = Float.parseFloat(values.get(j).toString()); annotations[gapmap[j]] = new Annotation("", value + "", ' ', value); } al.addAnnotation(new AlignmentAnnotation(Symname, Visname, annotations, min, max, winLength)); }*/ void parseResult() { int results = 0; // number of result sets received JobStateSummary finalState = new JobStateSummary(); try { for (int j = 0; j < jobs.length; j++) { finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]); if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults()) { results++; } } } catch (Exception ex) { Cache.log.error("Unexpected exception when processing results for " + altitle, ex); wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); } if (results > 0) { wsInfo.showResultsNewFrame .addActionListener(new java.awt.event.ActionListener() { public void actionPerformed( java.awt.event.ActionEvent evt) { displayResults(true); } }); wsInfo.mergeResults .addActionListener(new java.awt.event.ActionListener() { public void actionPerformed( java.awt.event.ActionEvent evt) { displayResults(false); } }); wsInfo.setResultsReady(); } else { wsInfo.setFinishedNoResults(); } } void displayResults(boolean newWindow) { // TODO: cope with multiple subjobs. if (jobs != null) { Alignment res = null; boolean msa=false; for (int jn = 0; jn < jobs.length; jn++) { Alignment jobres = null; JPredJob j = (JPredJob) jobs[jn]; if (j.hasResults()) { // hack - we only deal with all single seuqence predictions or all profile predictions msa = (j.msa!=null) ? true : msa; try { jalview.bin.Cache.log.debug("Parsing output of job " + jn); jobres = j.getResultSet(); jalview.bin.Cache.log.debug("Finished parsing output."); if (jobs.length==1) res = jobres; else { // do merge with other job results throw new Error("Multiple JNet subjob merging not yet implemented."); } } catch (Exception e) { jalview.bin.Cache.log.error( "JNet Client: JPred Annotation Parse Error", e); wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR); wsInfo.appendProgressText(j.jobnum, OutputHeader + "\n" + j.result.getStatus() + "\nInvalid JNet job result data!\n" + e.getMessage()); j.result.setBroken(true); } } } if (res != null) { if (newWindow) { AlignFrame af; if (input==null) { af = new AlignFrame(res); } else { java.lang.Object[] alandcolsel = input.getAlignmentAndColumnSelection(alignFrame.getViewport().getGapCharacter()); if (((SequenceI[])alandcolsel[0])[0].getLength()!=res.getWidth()) { if (msa) { throw new Error("Implementation Error! ColumnSelection from input alignment will not map to result alignment!"); } else { // test this. ((ColumnSelection) alandcolsel[1]).pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap()));//gapMap returns insert list, interpreted as delete list by pruneDeletions } } af = new AlignFrame(res, (ColumnSelection) alandcolsel[1]); } Desktop.addInternalFrame(af, altitle, AlignFrame.NEW_WINDOW_WIDTH, AlignFrame.NEW_WINDOW_HEIGHT); } else { Cache.log.info("Append results onto existing alignment."); } } } } void pollJob(WSJob job) throws Exception { job.result = server.getresult(job.jobId); } public boolean isCancellable() { return false; } public void cancelJob() { throw new Error("Implementation error!"); } public boolean canMergeResults() { return false; } } }