package jalview.ws2.client.ebi; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.net.URI; import java.util.List; import jalview.bin.Console; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.FileParse; import jalview.io.FormatAdapter; import jalview.io.StockholmFile; import jalview.ws.params.ArgumentI; import jalview.ws.params.simple.BooleanOption; import jalview.ws.params.simple.DoubleParameter; import jalview.ws.params.simple.IntegerParameter; import jalview.ws2.api.Credentials; import jalview.ws2.api.JobStatus; import jalview.ws2.api.WebServiceJobHandle; import jalview.ws2.client.api.AlignmentWebServiceClientI; import jalview.ws2.client.api.WebServiceClientI; import uk.ac.dundee.compbio.hmmerclient.PhmmerClient; import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest; import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest.SequenceDatabase; import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest.SubstitutionMatrix; public class PhmmerWSClient implements AlignmentWebServiceClientI { final PhmmerClient client; PhmmerWSClient(PhmmerClient client) { this.client = client; } @Override public String getUrl() { return client.getURL().toString(); } @Override public String getClientName() { return "ebi-job-dispatcher"; } @Override public WebServiceJobHandle submit(List sequences, List args, Credentials credentials) throws IOException { var request = PhmmerRequest.newBuilder(); String sequence = FileFormat.Fasta.getWriter(null) .print(new SequenceI[]{ sequences.get(0) }, false); request.sequence(new StringReader(sequence)); populateRequestArguments(request, args); var email = credentials.getEmail() != null ? credentials.getEmail() : "nouser@jalview.org"; var jobId = client.submit(request.build(), email); Console.debug("Phmmer client submitted new job with id " + jobId); return new WebServiceJobHandle( getClientName(), "phmmer", getUrl(), jobId); } private static void populateRequestArguments(PhmmerRequest.Builder request, List args) { boolean useBitScore = false; boolean useEValue = false; for (var arg : args) { if (arg.getName().equals("cut-offs")) if (arg.getValue().equals("E")) useEValue = true; else if (arg.getValue().equals("T")) useBitScore = true; else throw new IllegalArgumentException( "cut-offs argument contains value other than \"E\" or \"T\": " + arg.getValue()); } assert (useBitScore || useEValue) && !(useBitScore && useEValue); for (var arg : args) { switch (arg.getName()) { case "incE": request.incE(useEValue ? DoubleParameter.parseFloat(arg) : null); break; case "incdomE": request.incdomE(useEValue ? DoubleParameter.parseFloat(arg) : null); break; case "E": request.E(useEValue ? DoubleParameter.parseFloat(arg) : null); break; case "domE": request.domE(useEValue ? DoubleParameter.parseFloat(arg) : null); break; case "incT": request.incT(useBitScore ? DoubleParameter.parseFloat(arg) : null); break; case "incdomT": request.incdomT(useBitScore ? DoubleParameter.parseFloat(arg) : null); break; case "T": request.T(useBitScore ? DoubleParameter.parseFloat(arg) : null); break; case "domT": request.domT(useBitScore ? DoubleParameter.parseFloat(arg) : null); break; case "popen": request.popen(DoubleParameter.parseFloat(arg)); break; case "pextend": request.pextend(DoubleParameter.parseFloat(arg)); break; case "mx": request.mx(parseSubstitutionMatrix(arg)); break; case "nobias": request.noBias(BooleanOption.parseBoolean(arg)); break; case "compressedout": request.compressedOut(BooleanOption.parseBoolean(arg)); break; case "alignView": request.compressedOut(BooleanOption.parseBoolean(arg)); break; case "database": request.database(parseSequenceDatabase(arg)); break; case "evalue": request.evalue(DoubleParameter.parseFloat(arg)); break; case "nhits": request.nhits(IntegerParameter.parseInt(arg)); break; } } } private static SubstitutionMatrix parseSubstitutionMatrix(ArgumentI arg) { if (arg.getValue() == null) return null; switch (arg.getValue()) { case "BLOSUM45": return SubstitutionMatrix.BLOSUM45; case "BLOSUM62": return SubstitutionMatrix.BLOSUM62; case "BLOSUM90": return SubstitutionMatrix.BLOSUM90; case "PAM30": return SubstitutionMatrix.PAM30; case "PAM70": return SubstitutionMatrix.PAM70; default: throw new IllegalArgumentException( "invalid matrix " + arg.getValue()); } } private static SequenceDatabase parseSequenceDatabase(ArgumentI arg) { if (arg.getValue() == null) return null; switch (arg.getValue()) { case "swissprot": return SequenceDatabase.SWISS_PROT; case "uniprotrefprot": return SequenceDatabase.REFERENCE_PROTEOMES; case "uniprotkb": return SequenceDatabase.UNIPROTKB; case "pdb": return SequenceDatabase.PDB; case "rp75": return SequenceDatabase.RP75; case "rp55": return SequenceDatabase.RP55; case "rp35": return SequenceDatabase.RP35; case "rp15": return SequenceDatabase.RP15; case "ensembl": return SequenceDatabase.ENSEMBL; case "merops": return SequenceDatabase.MEROPS; case "qfo": return SequenceDatabase.QUEST_FOR_ORTHOLOGS; case "chembl": return SequenceDatabase.CHEMBL; default: throw new IllegalArgumentException( "invalid database " + arg.getValue()); } } @Override public JobStatus getStatus(WebServiceJobHandle job) throws IOException { var status = client.getStatus(job.getJobId()); switch (status) { case PENDING: return JobStatus.SUBMITTED; case QUEUED: return JobStatus.QUEUED; case RUNNING: return JobStatus.RUNNING; case FINISHED: return JobStatus.COMPLETED; case FAILURE: return JobStatus.FAILED; case ERROR: return JobStatus.SERVER_ERROR; case NOT_FOUND: return JobStatus.SERVER_ERROR; case UNDEFINED: return JobStatus.UNKNOWN; } return JobStatus.UNKNOWN; } @Override public String getLog(WebServiceJobHandle job) throws IOException { return ""; } @Override public String getErrorLog(WebServiceJobHandle job) throws IOException { return ""; } @Override public void cancel(WebServiceJobHandle job) throws IOException, UnsupportedOperationException { throw new UnsupportedOperationException( "ebi job dispatcher does not support job cancellation"); } /** * FIXME: Temporary hack */ @Override public AlignmentI getAlignment(WebServiceJobHandle job) throws IOException { URI url = client.getResultURL(job.getJobId(), "sto"); try(InputStream stream = client.getResultStream(job.getJobId(), "sto")) { StockholmFile file = new StockholmFile(new FileParse( new BufferedReader(new InputStreamReader(stream)), url.toString(), DataSourceType.URL)); var aln = new Alignment(file.getSeqsAsArray()); for (var annotation : file.getAnnotations()) aln.addAnnotation(annotation); return aln; } } }