9c5f14f6640dbafa2b8d7582a5bfc58fc26eab3f
[jalview.git] / src / jalview / ws2 / client / ebi / PhmmerWSClient.java
1 package jalview.ws2.client.ebi;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.io.StringReader;
8 import java.net.URI;
9 import java.util.List;
10
11 import jalview.bin.Console;
12 import jalview.datamodel.Alignment;
13 import jalview.datamodel.AlignmentI;
14 import jalview.datamodel.SequenceI;
15 import jalview.io.DataSourceType;
16 import jalview.io.FileFormat;
17 import jalview.io.FileParse;
18 import jalview.io.FormatAdapter;
19 import jalview.io.StockholmFile;
20 import jalview.ws.params.ArgumentI;
21 import jalview.ws.params.simple.BooleanOption;
22 import jalview.ws.params.simple.DoubleParameter;
23 import jalview.ws.params.simple.IntegerParameter;
24 import jalview.ws2.api.Credentials;
25 import jalview.ws2.api.JobStatus;
26 import jalview.ws2.api.WebServiceJobHandle;
27 import jalview.ws2.client.api.AlignmentWebServiceClientI;
28 import jalview.ws2.client.api.WebServiceClientI;
29 import uk.ac.dundee.compbio.hmmerclient.PhmmerClient;
30 import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest;
31 import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest.SequenceDatabase;
32 import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest.SubstitutionMatrix;
33
34 public class PhmmerWSClient implements AlignmentWebServiceClientI
35 {
36
37   final PhmmerClient client;
38
39   PhmmerWSClient(PhmmerClient client)
40   {
41     this.client = client;
42   }
43
44   @Override
45   public String getUrl()
46   {
47     return client.getURL().toString();
48   }
49
50   @Override
51   public String getClientName()
52   {
53     return "ebi-job-dispatcher";
54   }
55
56   @Override
57   public WebServiceJobHandle submit(List<SequenceI> sequences,
58           List<ArgumentI> args, Credentials credentials) throws IOException
59   {
60     var request = PhmmerRequest.newBuilder();
61     String sequence = FileFormat.Fasta.getWriter(null)
62             .print(new SequenceI[]{ sequences.get(0) }, false);
63     request.sequence(new StringReader(sequence));
64     populateRequestArguments(request, args);
65     var email = credentials.getEmail() != null ? credentials.getEmail() :
66       "nouser@jalview.org";
67     var jobId = client.submit(request.build(), email);
68     Console.debug("Phmmer client submitted new job with id " + jobId);
69     return new WebServiceJobHandle(
70             getClientName(), "phmmer", getUrl(), jobId);
71   }
72   
73   private static void populateRequestArguments(PhmmerRequest.Builder request, List<ArgumentI> args)
74   {
75     boolean useBitScore = false;
76     boolean useEValue = false;
77     for (var arg : args)
78     {
79       if (arg.getName().equals("cut-offs"))
80         if (arg.getValue().equals("E"))
81           useEValue = true;
82         else if (arg.getValue().equals("T"))
83           useBitScore = true;
84         else
85           throw new IllegalArgumentException(
86                   "cut-offs argument contains value other than \"E\" or \"T\": "
87                           + arg.getValue());
88     }
89     assert (useBitScore || useEValue) && !(useBitScore && useEValue);
90     for (var arg : args)
91     {
92       switch (arg.getName())
93       {
94       case "incE":
95         request.incE(useEValue ? DoubleParameter.parseFloat(arg) : null);
96         break;
97       case "incdomE":
98         request.incdomE(useEValue ? DoubleParameter.parseFloat(arg) : null);
99         break;
100       case "E":
101         request.E(useEValue ? DoubleParameter.parseFloat(arg) : null);
102         break;
103       case "domE":
104         request.domE(useEValue ? DoubleParameter.parseFloat(arg) : null);
105         break;
106       case "incT":
107         request.incT(useBitScore ? DoubleParameter.parseFloat(arg) : null);
108         break;
109       case "incdomT":
110         request.incdomT(useBitScore ? DoubleParameter.parseFloat(arg) : null);
111         break;
112       case "T":
113         request.T(useBitScore ? DoubleParameter.parseFloat(arg) : null);
114         break;
115       case "domT":
116         request.domT(useBitScore ? DoubleParameter.parseFloat(arg) : null);
117         break;
118       case "popen":
119         request.popen(DoubleParameter.parseFloat(arg));
120         break;
121       case "pextend":
122         request.pextend(DoubleParameter.parseFloat(arg));
123         break;
124       case "mx":
125         request.mx(parseSubstitutionMatrix(arg));
126         break;
127       case "nobias":
128         request.noBias(BooleanOption.parseBoolean(arg));
129         break;
130       case "compressedout":
131         request.compressedOut(BooleanOption.parseBoolean(arg));
132         break;
133       case "alignView":
134         request.compressedOut(BooleanOption.parseBoolean(arg));
135         break;
136       case "database":
137         request.database(parseSequenceDatabase(arg));
138         break;
139       case "evalue":
140         request.evalue(DoubleParameter.parseFloat(arg));
141         break;
142       case "nhits":
143         request.nhits(IntegerParameter.parseInt(arg));
144         break;
145       }
146     }
147   }
148
149   private static SubstitutionMatrix parseSubstitutionMatrix(ArgumentI arg)
150   {
151     if (arg.getValue() == null)
152       return null;
153     switch (arg.getValue())
154     {
155     case "BLOSUM45":
156       return SubstitutionMatrix.BLOSUM45;
157     case "BLOSUM62":
158       return SubstitutionMatrix.BLOSUM62;
159     case "BLOSUM90":
160       return SubstitutionMatrix.BLOSUM90;
161     case "PAM30":
162       return SubstitutionMatrix.PAM30;
163     case "PAM70":
164       return SubstitutionMatrix.PAM70;
165     default:
166       throw new IllegalArgumentException(
167               "invalid matrix " + arg.getValue());
168     }
169   }
170
171   private static SequenceDatabase parseSequenceDatabase(ArgumentI arg)
172   {
173     if (arg.getValue() == null)
174       return null;
175     switch (arg.getValue())
176     {
177     case "swissprot":
178       return SequenceDatabase.SWISS_PROT;
179     case "uniprotrefprot":
180       return SequenceDatabase.REFERENCE_PROTEOMES;
181     case "uniprotkb":
182       return SequenceDatabase.UNIPROTKB;
183     case "pdb":
184       return SequenceDatabase.PDB;
185     case "rp75":
186       return SequenceDatabase.RP75;
187     case "rp55":
188       return SequenceDatabase.RP55;
189     case "rp35":
190       return SequenceDatabase.RP35;
191     case "rp15":
192       return SequenceDatabase.RP15;
193     case "ensembl":
194       return SequenceDatabase.ENSEMBL;
195     case "merops":
196       return SequenceDatabase.MEROPS;
197     case "qfo":
198       return SequenceDatabase.QUEST_FOR_ORTHOLOGS;
199     case "chembl":
200       return SequenceDatabase.CHEMBL;
201     default:
202       throw new IllegalArgumentException(
203               "invalid database " + arg.getValue());
204     }
205   }
206
207   @Override
208   public JobStatus getStatus(WebServiceJobHandle job) throws IOException
209   {
210     var status = client.getStatus(job.getJobId());
211     switch (status)
212     {
213     case PENDING: return JobStatus.SUBMITTED;
214     case QUEUED: return JobStatus.QUEUED;
215     case RUNNING: return JobStatus.RUNNING;
216     case FINISHED: return JobStatus.COMPLETED;
217     case FAILURE: return JobStatus.FAILED;
218     case ERROR: return JobStatus.SERVER_ERROR;
219     case NOT_FOUND: return JobStatus.SERVER_ERROR;
220     case UNDEFINED: return JobStatus.UNKNOWN;
221     }
222     return JobStatus.UNKNOWN;
223   }
224
225   @Override
226   public String getLog(WebServiceJobHandle job) throws IOException
227   {
228     return "";
229   }
230
231   @Override
232   public String getErrorLog(WebServiceJobHandle job) throws IOException
233   {
234     return "";
235   }
236
237   @Override
238   public void cancel(WebServiceJobHandle job)
239           throws IOException, UnsupportedOperationException
240   {
241     throw new UnsupportedOperationException(
242             "ebi job dispatcher does not support job cancellation");
243   }
244
245   /**
246    * FIXME: Temporary hack
247    */
248   @Override
249   public AlignmentI getAlignment(WebServiceJobHandle job) throws IOException
250   {
251     URI url = client.getResultURL(job.getJobId(), "sto");
252     try(InputStream stream = client.getResultStream(job.getJobId(), "sto"))
253     {
254       StockholmFile file = new StockholmFile(new FileParse(
255               new BufferedReader(new InputStreamReader(stream)),
256               url.toString(), DataSourceType.URL));
257       var aln = new Alignment(file.getSeqsAsArray());
258       for (var annotation : file.getAnnotations())
259         aln.addAnnotation(annotation);
260       return aln;
261     }
262   }
263 }