1 package jalview.ws2.slivka;
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.Collection;
10 import java.util.EnumMap;
11 import java.util.HashSet;
12 import java.util.List;
15 import jalview.bin.Cache;
16 import jalview.datamodel.AlignmentI;
17 import jalview.datamodel.SequenceI;
18 import jalview.io.DataSourceType;
19 import jalview.io.FileFormat;
20 import jalview.io.FileFormatI;
21 import jalview.io.FormatAdapter;
22 import jalview.ws.gui.WsJob;
23 import jalview.ws.params.ArgumentI;
24 import jalview.ws.params.ParamDatastoreI;
25 import jalview.ws.params.WsParamSetI;
26 import jalview.ws.slivkaws.SlivkaDatastore;
27 import jalview.ws2.WebServiceI;
28 import jalview.ws2.operations.Operation;
29 import jalview.ws2.ResultSupplier;
30 import jalview.ws2.WSJob;
31 import jalview.ws2.WSJobStatus;
32 import javajs.http.ClientProtocolException;
33 import uk.ac.dundee.compbio.slivkaclient.Job;
34 import uk.ac.dundee.compbio.slivkaclient.Parameter;
35 import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
36 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
37 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
39 public class SlivkaWebService implements WebServiceI
41 protected final SlivkaClient client;
43 protected final SlivkaService service;
45 protected SlivkaDatastore store = null;
47 protected final ArrayList<Operation> operations = new ArrayList<>();
49 protected int typeFlags = 0;
51 protected static final EnumMap<Job.Status, WSJobStatus> statusMap = new EnumMap<>(
54 statusMap.put(Job.Status.PENDING, WSJobStatus.SUBMITTED);
55 statusMap.put(Job.Status.REJECTED, WSJobStatus.INVALID);
56 statusMap.put(Job.Status.ACCEPTED, WSJobStatus.QUEUED);
57 statusMap.put(Job.Status.QUEUED, WSJobStatus.QUEUED);
58 statusMap.put(Job.Status.RUNNING, WSJobStatus.RUNNING);
59 statusMap.put(Job.Status.COMPLETED, WSJobStatus.FINISHED);
60 statusMap.put(Job.Status.INTERRUPTED, WSJobStatus.CANCELLED);
61 statusMap.put(Job.Status.DELETED, WSJobStatus.CANCELLED);
62 statusMap.put(Job.Status.FAILED, WSJobStatus.FAILED);
63 statusMap.put(Job.Status.ERROR, WSJobStatus.SERVER_ERROR);
64 statusMap.put(Job.Status.UNKNOWN, WSJobStatus.UNKNOWN);
67 public SlivkaWebService(SlivkaClient client, SlivkaService service)
70 this.service = service;
74 public String getHostName()
76 return client.getUrl().toString();
80 public String getProviderName()
86 public String getName()
88 return service.getName();
92 public String getDescription()
94 return service.getDescription();
98 public List<Operation> getOperations()
103 void addOperation(Operation operation)
105 operations.add(operation);
108 void removeOperation(Operation operation)
110 operations.remove(operation);
114 public boolean hasParameters()
116 return getParamStore().getServiceParameters().size() > 0;
120 public ParamDatastoreI getParamStore()
124 store = new SlivkaDatastore(service);
130 public String submit(List<SequenceI> sequences, List<ArgumentI> args)
133 var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
134 for (Parameter param : service.getParameters())
136 if (param instanceof Parameter.FileParameter)
138 // if finds a file input, gives it sequences stream
139 Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
141 switch (fileParam.getMediaType())
143 case "application/pfam":
144 format = FileFormat.Pfam;
146 case "application/stockholm":
147 format = FileFormat.Stockholm;
149 case "application/clustal":
150 format = FileFormat.Clustal;
152 case "application/fasta":
154 format = FileFormat.Fasta;
157 InputStream stream = new ByteArrayInputStream(format.getWriter(null)
158 .print(sequences.toArray(new SequenceI[0]), false)
160 request.addFile(param.getId(), stream);
165 for (ArgumentI arg : args)
167 // multiple choice field names are name$number to avoid duplications
168 // the number is stripped here
169 String paramId = arg.getName().split("\\$", 2)[0];
170 Parameter param = service.getParameter(paramId);
171 if (param instanceof Parameter.FlagParameter)
173 if (arg.getValue() != null && !arg.getValue().isBlank())
174 request.addData(paramId, true);
176 request.addData(paramId, false);
180 request.addData(paramId, arg.getValue());
184 var job = service.submitJob(request);
189 public void updateProgress(WSJob job) throws IOException
191 var slivkaJob = client.getJob(job.getJobId());
192 job.setStatus(statusMap.get(slivkaJob.getStatus()));
193 Collection<RemoteFile> files = slivkaJob.getResults();
194 for (RemoteFile f : files)
196 if (f.getLabel().equals("log"))
198 ByteArrayOutputStream stream = new ByteArrayOutputStream();
200 job.setLog(stream.toString("UTF-8"));
202 else if (f.getLabel().equals("error-log"))
204 ByteArrayOutputStream stream = new ByteArrayOutputStream();
206 job.setErrorLog(stream.toString("UTF-8"));
212 public void cancel(WSJob job) throws IOException
214 Cache.log.warn("Slivka does not support job cancellation yet.");
218 public boolean handleSubmissionError(WSJob job, Exception ex)
220 if (ex instanceof ClientProtocolException)
222 Cache.log.error("Job submission failed due to exception.", ex);
229 public boolean handleCollectionError(WSJob job, Exception ex)
231 // TODO Auto-generated method stub
235 public AlignmentI getAlignment(WSJob job) throws IOException
237 Collection<RemoteFile> files;
238 var slivkaJob = client.getJob(job.getJobId());
239 files = slivkaJob.getResults();
240 for (RemoteFile f : files)
242 if (f.getMediaType().equals("application/clustal"))
244 return new FormatAdapter().readFile(f.getContentUrl().toString(),
245 DataSourceType.URL, FileFormat.Clustal);
247 else if (f.getMediaType().equals("application/fasta"))
249 return new FormatAdapter().readFile(f.getContentUrl().toString(),
250 DataSourceType.URL, FileFormat.Fasta);
257 public String toString()
259 return String.format("SlivkaWebService[%s]", getName());