1 package jalview.ws2.client.slivka;
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.nio.charset.StandardCharsets;
9 import java.util.EnumMap;
10 import java.util.List;
11 import java.util.regex.Pattern;
13 import jalview.bin.Cache;
14 import jalview.datamodel.AlignmentI;
15 import jalview.datamodel.SequenceI;
16 import jalview.io.DataSourceType;
17 import jalview.io.FileFormat;
18 import jalview.io.FormatAdapter;
19 import jalview.ws.params.ArgumentI;
20 import jalview.ws2.api.Credentials;
21 import jalview.ws2.api.JobStatus;
22 import jalview.ws2.api.WebServiceJobHandle;
23 import jalview.ws2.client.api.AlignmentWebServiceClientI;
24 import jalview.ws2.client.api.WebServiceClientI;
25 import uk.ac.dundee.compbio.slivkaclient.Job;
26 import uk.ac.dundee.compbio.slivkaclient.Parameter;
27 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
28 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
30 public class SlivkaWSClient implements WebServiceClientI
32 final SlivkaService service;
34 final SlivkaClient client;
36 SlivkaWSClient(SlivkaService service)
38 this.service = service;
39 this.client = service.getClient();
43 public String getUrl()
45 return client.getUrl().toString();
49 public String getClientName()
54 // pattern for matching media types
55 static final Pattern mediaTypePattern = Pattern.compile("(?:text|application)\\/(?:x-)?(\\w+)");
58 public WebServiceJobHandle submit(List<SequenceI> sequences,
59 List<ArgumentI> args, Credentials credentials) throws IOException
61 var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
62 for (Parameter param : service.getParameters())
64 // TODO: restrict input sequences parameter name to "sequences"
65 if (param instanceof Parameter.FileParameter)
67 Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
68 FileFormat format = null;
69 var match = mediaTypePattern.matcher(fileParam.getMediaType());
72 String fmt = match.group(1);
73 if (fmt.equalsIgnoreCase("pfam"))
74 format = FileFormat.Pfam;
75 else if (fmt.equalsIgnoreCase("stockholm"))
76 format = FileFormat.Stockholm;
77 else if (fmt.equalsIgnoreCase("clustal"))
78 format = FileFormat.Clustal;
79 else if (fmt.equalsIgnoreCase("fasta"))
80 format = FileFormat.Fasta;
84 Cache.log.warn(String.format(
85 "Unknown input format %s, assuming fasta.",
86 fileParam.getMediaType()));
87 format = FileFormat.Fasta;
89 InputStream stream = new ByteArrayInputStream(format.getWriter(null)
90 .print(sequences.toArray(new SequenceI[0]), false)
92 request.addFile(param.getId(), stream);
97 for (ArgumentI arg : args)
99 // multiple choice field names are name$number to avoid duplications
100 // the number is stripped here
101 String paramId = arg.getName().split("\\$", 2)[0];
102 Parameter param = service.getParameter(paramId);
103 if (param instanceof Parameter.FlagParameter)
105 if (arg.getValue() != null && !arg.getValue().isBlank())
106 request.addData(paramId, true);
108 request.addData(paramId, false);
110 else if (param instanceof Parameter.FileParameter)
112 request.addFile(paramId, new File(arg.getValue()));
116 request.addData(paramId, arg.getValue());
120 var job = service.submitJob(request);
121 return createJobHandle(job.getId());
124 protected WebServiceJobHandle createJobHandle(String jobId)
126 return new WebServiceJobHandle(
127 getClientName(), service.getName(), client.getUrl().toString(),
132 public JobStatus getStatus(WebServiceJobHandle job) throws IOException
134 var slivkaJob = client.getJob(job.getJobId());
135 return statusMap.getOrDefault(slivkaJob.getStatus(), JobStatus.UNKNOWN);
138 protected static final EnumMap<Job.Status, JobStatus> statusMap = new EnumMap<>(Job.Status.class);
141 statusMap.put(Job.Status.PENDING, JobStatus.SUBMITTED);
142 statusMap.put(Job.Status.REJECTED, JobStatus.INVALID);
143 statusMap.put(Job.Status.ACCEPTED, JobStatus.SUBMITTED);
144 statusMap.put(Job.Status.QUEUED, JobStatus.QUEUED);
145 statusMap.put(Job.Status.RUNNING, JobStatus.RUNNING);
146 statusMap.put(Job.Status.COMPLETED, JobStatus.COMPLETED);
147 statusMap.put(Job.Status.INTERRUPTED, JobStatus.CANCELLED);
148 statusMap.put(Job.Status.DELETED, JobStatus.CANCELLED);
149 statusMap.put(Job.Status.FAILED, JobStatus.FAILED);
150 statusMap.put(Job.Status.ERROR, JobStatus.SERVER_ERROR);
151 statusMap.put(Job.Status.UNKNOWN, JobStatus.UNKNOWN);
155 public String getLog(WebServiceJobHandle job) throws IOException
157 var slivkaJob = client.getJob(job.getJobId());
158 for (var f : slivkaJob.getResults())
160 if (f.getLabel().equals("log"))
162 ByteArrayOutputStream stream = new ByteArrayOutputStream();
164 return stream.toString(StandardCharsets.UTF_8);
171 public String getErrorLog(WebServiceJobHandle job) throws IOException
173 var slivkaJob = client.getJob(job.getJobId());
174 for (var f : slivkaJob.getResults())
176 if (f.getLabel().equals("error-log"))
178 ByteArrayOutputStream stream = new ByteArrayOutputStream();
180 return stream.toString(StandardCharsets.UTF_8);
187 public void cancel(WebServiceJobHandle job)
188 throws IOException, UnsupportedOperationException
190 throw new UnsupportedOperationException(
191 "slivka client does not support job cancellation");
195 class SlivkaAlignmentWSClient extends SlivkaWSClient
196 implements AlignmentWebServiceClientI
199 SlivkaAlignmentWSClient(SlivkaService service)
205 public AlignmentI getAlignment(WebServiceJobHandle job) throws IOException
207 var slivkaJob = client.getJob(job.getJobId());
208 for (var f : slivkaJob.getResults())
210 // TODO: restrict result file label to "alignment"
212 var match = mediaTypePattern.matcher(f.getMediaType());
215 String fmt = match.group(1);
216 if (fmt.equalsIgnoreCase("clustal"))
217 format = FileFormat.Clustal;
218 else if (fmt.equalsIgnoreCase("fasta"))
219 format = FileFormat.Fasta;
222 return new FormatAdapter().readFile(f.getContentUrl().toString(),
223 DataSourceType.URL, format);
225 Cache.log.warn("No alignment found on the server");
226 throw new IOException("no alignment found");