Clover icon

Coverage Report

  1. Project Clover database Wed Dec 3 2025 17:03:17 GMT
  2. Package jalview.ws2.client.slivka

File SlivkaWSClient.java

 

Coverage histogram

../../../../img/srcFileCovDistChart2.png
54% of files have more coverage

Code metrics

48
101
14
3
288
259
39
0.39
7.21
4.67
2.79

Classes

Class Line # Actions
SlivkaWSClient 43 64 24
0.1515%
SlivkaAlignmentWSClient 206 15 5
0.086956528.7%
SlivkaAnnotationWSClient 241 22 10
0.055%
 

Contributing tests

This file is covered by 107 tests. .

Source view

1    package jalview.ws2.client.slivka;
2   
3    import java.io.ByteArrayInputStream;
4    import java.io.ByteArrayOutputStream;
5    import java.io.File;
6    import java.io.IOException;
7    import java.io.InputStream;
8    import java.nio.charset.StandardCharsets;
9    import java.util.Arrays;
10    import java.util.Collections;
11    import java.util.EnumMap;
12    import java.util.List;
13    import java.util.Map;
14    import java.util.regex.Pattern;
15   
16    import jalview.api.FeatureColourI;
17    import jalview.bin.Cache;
18    import jalview.bin.Console;
19    import jalview.datamodel.Alignment;
20    import jalview.datamodel.AlignmentAnnotation;
21    import jalview.datamodel.AlignmentI;
22    import jalview.datamodel.SequenceI;
23    import jalview.datamodel.features.FeatureMatcherSetI;
24    import jalview.io.AnnotationFile;
25    import jalview.io.DataSourceType;
26    import jalview.io.FeaturesFile;
27    import jalview.io.FileFormat;
28    import jalview.io.FormatAdapter;
29    import jalview.ws.params.ArgumentI;
30    import jalview.ws2.api.Credentials;
31    import jalview.ws2.api.JobStatus;
32    import jalview.ws2.api.WebServiceJobHandle;
33    import jalview.ws2.client.api.AlignmentWebServiceClientI;
34    import jalview.ws2.client.api.AnnotationWebServiceClientI;
35    import jalview.ws2.client.api.WebServiceClientI;
36    import uk.ac.dundee.compbio.slivkaclient.Job;
37    import uk.ac.dundee.compbio.slivkaclient.Parameter;
38    import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
39    import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
40   
41    import static java.lang.String.format;
42   
 
43    public class SlivkaWSClient implements WebServiceClientI
44    {
45    final SlivkaService service;
46   
47    final SlivkaClient client;
48   
 
49  1494 toggle SlivkaWSClient(SlivkaClient client, SlivkaService service)
50    {
51  1494 this.service = service;
52  1494 this.client = client;
53    }
54   
 
55  0 toggle @Override
56    public String getUrl()
57    {
58  0 return client.getUrl().toString();
59    }
60   
 
61  0 toggle @Override
62    public String getClientName()
63    {
64  0 return "slivka";
65    }
66   
67    // pattern for matching media types
68    static final Pattern mediaTypePattern = Pattern.compile(
69    "(?:text|application)\\/(?:x-)?([\\w-]+)");
70   
 
71  0 toggle @Override
72    public WebServiceJobHandle submit(List<SequenceI> sequences,
73    List<ArgumentI> args, Credentials credentials) throws IOException
74    {
75  0 var request = new uk.ac.dundee.compbio.slivkaclient.RequestValues();
76  0 for (Parameter param : service.getParameters())
77    {
78    // TODO: restrict input sequences parameter name to "sequences"
79  0 if (param instanceof Parameter.FileParameter)
80    {
81  0 Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
82  0 FileFormat format = null;
83  0 var match = mediaTypePattern.matcher(fileParam.getMediaType());
84  0 if (match.find())
85    {
86  0 String fmt = match.group(1);
87  0 if (fmt.equalsIgnoreCase("pfam"))
88  0 format = FileFormat.Pfam;
89  0 else if (fmt.equalsIgnoreCase("stockholm"))
90  0 format = FileFormat.Stockholm;
91  0 else if (fmt.equalsIgnoreCase("clustal"))
92  0 format = FileFormat.Clustal;
93  0 else if (fmt.equalsIgnoreCase("fasta"))
94  0 format = FileFormat.Fasta;
95    }
96  0 if (format == null)
97    {
98  0 Console.warn(String.format(
99    "Unknown input format %s, assuming fasta.",
100    fileParam.getMediaType()));
101  0 format = FileFormat.Fasta;
102    }
103  0 InputStream stream = new ByteArrayInputStream(format.getWriter(null)
104    .print(sequences.toArray(new SequenceI[0]), false)
105    .getBytes());
106  0 request.addFile(param.getId(), stream);
107    }
108    }
109  0 if (args != null)
110    {
111  0 for (ArgumentI arg : args)
112    {
113    // multiple choice field names are name$number to avoid duplications
114    // the number is stripped here
115  0 String paramId = arg.getName().split("\\$", 2)[0];
116  0 Parameter param = service.getParameter(paramId);
117  0 if (param instanceof Parameter.FlagParameter)
118    {
119  0 if (arg.getValue() != null && !arg.getValue().isEmpty())
120  0 request.addData(paramId, true);
121    else
122  0 request.addData(paramId, false);
123    }
124  0 else if (param instanceof Parameter.FileParameter)
125    {
126  0 request.addFile(paramId, new File(arg.getValue()));
127    }
128    else
129    {
130  0 request.addData(paramId, arg.getValue());
131    }
132    }
133    }
134  0 var jobId = client.submitJob(service, request);
135  0 return createJobHandle(jobId);
136    }
137   
 
138  0 toggle protected WebServiceJobHandle createJobHandle(String jobId)
139    {
140  0 return new WebServiceJobHandle(
141    getClientName(), service.getName(), client.getUrl().toString(),
142    jobId);
143    }
144   
 
145  0 toggle @Override
146    public JobStatus getStatus(WebServiceJobHandle job) throws IOException
147    {
148  0 return statusMap.getOrDefault(client.fetchJobStatus(job.getJobId()), JobStatus.UNKNOWN);
149    }
150   
151    protected static final EnumMap<Job.Status, JobStatus> statusMap = new EnumMap<>(Job.Status.class);
 
152  6 toggle static
153    {
154  6 statusMap.put(Job.Status.PENDING, JobStatus.SUBMITTED);
155  6 statusMap.put(Job.Status.REJECTED, JobStatus.INVALID);
156  6 statusMap.put(Job.Status.ACCEPTED, JobStatus.SUBMITTED);
157  6 statusMap.put(Job.Status.QUEUED, JobStatus.QUEUED);
158  6 statusMap.put(Job.Status.RUNNING, JobStatus.RUNNING);
159  6 statusMap.put(Job.Status.COMPLETED, JobStatus.COMPLETED);
160  6 statusMap.put(Job.Status.INTERRUPTED, JobStatus.CANCELLED);
161  6 statusMap.put(Job.Status.DELETED, JobStatus.CANCELLED);
162  6 statusMap.put(Job.Status.FAILED, JobStatus.FAILED);
163  6 statusMap.put(Job.Status.ERROR, JobStatus.SERVER_ERROR);
164  6 statusMap.put(Job.Status.UNKNOWN, JobStatus.UNKNOWN);
165    }
166   
 
167  0 toggle @Override
168    public String getLog(WebServiceJobHandle job) throws IOException
169    {
170  0 for (var f : client.fetchFilesList(job.getJobId()))
171    {
172  0 if (f.getLabel().equals("log"))
173    {
174  0 ByteArrayOutputStream stream = new ByteArrayOutputStream();
175  0 client.writeFileTo(f, stream);
176  0 return stream.toString("UTF-8");
177    }
178    }
179  0 return "";
180    }
181   
 
182  0 toggle @Override
183    public String getErrorLog(WebServiceJobHandle job) throws IOException
184    {
185  0 for (var f : client.fetchFilesList(job.getJobId()))
186    {
187  0 if (f.getLabel().equals("error-log"))
188    {
189  0 ByteArrayOutputStream stream = new ByteArrayOutputStream();
190  0 client.writeFileTo(f, stream);
191  0 return stream.toString("UTF-8");
192    }
193    }
194  0 return "";
195    }
196   
 
197  0 toggle @Override
198    public void cancel(WebServiceJobHandle job)
199    throws IOException, UnsupportedOperationException
200    {
201  0 Console.warn(
202    "slivka client does not support job cancellation");
203    }
204    }
205   
 
206    class SlivkaAlignmentWSClient extends SlivkaWSClient
207    implements AlignmentWebServiceClientI
208    {
209   
 
210  810 toggle SlivkaAlignmentWSClient(SlivkaClient client, SlivkaService service)
211    {
212  810 super(client, service);
213    }
214   
 
215  0 toggle @Override
216    public AlignmentI getAlignment(WebServiceJobHandle job) throws IOException
217    {
218  0 for (var f : client.fetchFilesList(job.getJobId()))
219    {
220    // TODO: restrict result file label to "alignment"
221  0 FileFormat format;
222  0 var match = mediaTypePattern.matcher(f.getMediaType());
223  0 if (!match.find())
224  0 continue;
225  0 String fmt = match.group(1);
226  0 if (fmt.equalsIgnoreCase("clustal"))
227  0 format = FileFormat.Clustal;
228  0 else if (fmt.equalsIgnoreCase("fasta"))
229  0 format = FileFormat.Fasta;
230    else
231  0 continue;
232  0 return new FormatAdapter().readFile(f.getContentUrl().toString(),
233    DataSourceType.URL, format);
234    }
235  0 Console.warn("No alignment found on the server");
236  0 throw new IOException("no alignment found");
237    }
238   
239    }
240   
 
241    class SlivkaAnnotationWSClient extends SlivkaWSClient
242    implements AnnotationWebServiceClientI
243    {
 
244  684 toggle SlivkaAnnotationWSClient(SlivkaClient client, SlivkaService service)
245    {
246  684 super(client, service);
247    }
248   
 
249  0 toggle @Override
250    public List<AlignmentAnnotation> attachAnnotations(WebServiceJobHandle job,
251    List<SequenceI> sequences, Map<String, FeatureColourI> colours,
252    Map<String, FeatureMatcherSetI> filters) throws IOException
253    {
254  0 var aln = new Alignment(sequences.toArray(new SequenceI[sequences.size()]));
255  0 boolean featPresent = false, annotPresent = false;
256  0 for (var f : client.fetchFilesList(job.getJobId()))
257    {
258    // TODO: restrict file label to "annotations" or "features"
259  0 var match = mediaTypePattern.matcher(f.getMediaType());
260  0 if (!match.find())
261  0 continue;
262  0 String fmt = match.group(1);
263  0 if (fmt.equalsIgnoreCase("jalview-annotations"))
264    {
265  0 annotPresent = new AnnotationFile().readAnnotationFileWithCalcId(
266    aln, service.getId(), f.getContentUrl().toString(),
267    DataSourceType.URL);
268  0 if (annotPresent)
269  0 Console.debug(format("loaded annotations for %s", service.getId()));
270    }
271  0 else if (fmt.equalsIgnoreCase("jalview-features"))
272    {
273  0 FeaturesFile ff = new FeaturesFile(f.getContentUrl().toString(),
274    DataSourceType.URL);
275    // TODO: determine if relaxed id matching is T/F
276  0 featPresent = ff.parse(aln, colours, filters, false, true);
277  0 if (featPresent)
278  0 Console.debug(format("loaded features for %s", service.getId()));
279    }
280    }
281  0 if (!annotPresent)
282  0 Console.debug(format("no annotations found for %s", service.getId()));
283  0 if (!featPresent)
284  0 Console.debug(format("no features found for %s", service.getId()));
285  0 return aln.getAlignmentAnnotation() != null ? Arrays.asList(aln.getAlignmentAnnotation())
286    : Collections.emptyList();
287    }
288    }