e7800ad805ac5513e03d630815d7134e238ac4a0
[jalview.git] / src / jalview / ws2 / slivka / SlivkaWebService.java
1 package jalview.ws2.slivka;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collection;
9 import java.util.EnumMap;
10 import java.util.HashSet;
11 import java.util.List;
12 import java.util.Set;
13
14 import jalview.bin.Cache;
15 import jalview.datamodel.AlignmentI;
16 import jalview.datamodel.SequenceI;
17 import jalview.io.DataSourceType;
18 import jalview.io.FileFormat;
19 import jalview.io.FileFormatI;
20 import jalview.io.FormatAdapter;
21 import jalview.ws.gui.WsJob;
22 import jalview.ws.params.ArgumentI;
23 import jalview.ws.params.ParamDatastoreI;
24 import jalview.ws.params.WsParamSetI;
25 import jalview.ws.slivkaws.SlivkaDatastore;
26 import jalview.ws2.WebServiceI;
27 import jalview.ws2.operations.Operation;
28 import jalview.ws2.ResultSupplier;
29 import jalview.ws2.WSJob;
30 import jalview.ws2.WSJobStatus;
31 import javajs.http.ClientProtocolException;
32 import uk.ac.dundee.compbio.slivkaclient.Job;
33 import uk.ac.dundee.compbio.slivkaclient.Parameter;
34 import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
35 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
36 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
37
38 public class SlivkaWebService implements WebServiceI
39 {
40   protected final SlivkaClient client;
41   protected final SlivkaService service;
42   protected SlivkaDatastore store = null;
43   protected final String operation;
44   protected final ArrayList<Operation> operations = new ArrayList<>();
45   protected int typeFlags = 0;
46
47   protected static final EnumMap<Job.Status, WsJob.JobState> stateMap = new EnumMap<>(Job.Status.class);
48   {
49     stateMap.put(Job.Status.PENDING, WsJob.JobState.QUEUED);
50     stateMap.put(Job.Status.REJECTED, WsJob.JobState.INVALID);
51     stateMap.put(Job.Status.ACCEPTED, WsJob.JobState.QUEUED);
52     stateMap.put(Job.Status.QUEUED, WsJob.JobState.QUEUED);
53     stateMap.put(Job.Status.RUNNING, WsJob.JobState.RUNNING);
54     stateMap.put(Job.Status.COMPLETED, WsJob.JobState.FINISHED);
55     stateMap.put(Job.Status.INTERRUPTED, WsJob.JobState.CANCELLED);
56     stateMap.put(Job.Status.DELETED, WsJob.JobState.CANCELLED);
57     stateMap.put(Job.Status.FAILED, WsJob.JobState.FAILED);
58     stateMap.put(Job.Status.ERROR, WsJob.JobState.SERVERERROR);
59     stateMap.put(Job.Status.UNKNOWN, WsJob.JobState.UNKNOWN);
60   }
61   protected final Set<WsJob.JobState> failedStates = new HashSet<>(Arrays.asList(
62       WsJob.JobState.INVALID, WsJob.JobState.BROKEN, WsJob.JobState.FAILED,
63       WsJob.JobState.SERVERERROR, WsJob.JobState.CANCELLED
64   ));
65
66   public SlivkaWebService(SlivkaClient client, SlivkaService service, String operation) {
67     this.client = client;
68     this.service = service;
69     this.operation = operation;
70   }
71
72   @Override
73   public String getHostName() { return client.getUrl().toString(); }
74
75   @Override
76   public String getProviderName() { return "slivka"; }
77
78   @Override
79   public String getName() { return service.getName(); }
80
81   @Override
82   public String getDescription() { return service.getDescription(); }
83
84   @Override
85   public String getOperationType() { return operation; }
86
87   @Override
88   public List<Operation> getOperations() {
89     return operations;
90   }
91
92   void addOperation(Operation operation) {
93     operations.add(operation);
94   }
95
96   void removeOperation(Operation operation) {
97     operations.remove(operation);
98   }
99
100   @Override
101   public boolean hasParameters() {
102     return getParamStore().getServiceParameters().size() > 0;
103   }
104
105   @Override
106   public ParamDatastoreI getParamStore() {
107     if (store == null) {
108       store = new SlivkaDatastore(service);
109     }
110     return store;
111   }
112
113   @Override
114   public String submit(List<SequenceI> sequences, List<ArgumentI> args) throws IOException
115   {
116     var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
117     for (Parameter param : service.getParameters()) {
118       if (param instanceof Parameter.FileParameter) {
119         // if finds a file input, gives it sequences stream
120         Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
121         FileFormat format;
122         switch (fileParam.getMediaType()) {
123         case "application/pfam":
124           format = FileFormat.Pfam;
125           break;
126         case "application/stockholm":
127           format = FileFormat.Stockholm;
128           break;
129         case "application/clustal":
130           format = FileFormat.Clustal;
131           break;
132         case "application/fasta":
133         default:
134           format = FileFormat.Fasta;
135           break;
136         }
137         InputStream stream = new ByteArrayInputStream(
138                 format.getWriter(null)
139                 .print(sequences.toArray(new SequenceI[0]), false)
140                 .getBytes());
141         request.addFile(param.getId(), stream);
142       }
143     }
144     if (args != null) {
145       for (ArgumentI arg : args) {
146         // multiple choice field names are name$number to avoid duplications
147         // the number is stripped here
148         String paramId = arg.getName().split("\\$", 2)[0];
149         Parameter param = service.getParameter(paramId);
150         if (param instanceof Parameter.FlagParameter) {
151           if (arg.getValue() != null && !arg.getValue().isBlank())
152             request.addData(paramId, true);
153           else
154             request.addData(paramId, false);
155         }
156         else
157         {
158           request.addData(paramId, arg.getValue());
159         }
160       }
161     }
162     var job = service.submitJob(request);
163     return job.getId();
164   }
165
166   @Override
167   public void updateProgress(WSJob job)
168           throws IOException
169   {
170     // TODO Auto-generated method stub
171
172   }
173
174   @Override
175   public void cancel(WSJob job) throws IOException
176   {
177     Cache.log.warn("Slivka does not support job cancellation yet.");
178   }
179
180   @Override
181   public boolean handleSubmissionError(WSJob job, Exception ex)
182   {
183     if (ex instanceof ClientProtocolException) {
184       Cache.log.error("Job submission failed due to exception.", ex);
185       return true;
186     }
187     return false;
188   }
189
190   @Override
191   public boolean handleCollectionError(WSJob job, Exception ex)
192   {
193     // TODO Auto-generated method stub
194     return false;
195   }
196
197   public AlignmentI getAlignment(WSJob job) throws IOException {
198     Collection<RemoteFile> files;
199     var slivkaJob = client.getJob(job.getJobId());
200     files = slivkaJob.getResults();
201     for (RemoteFile f : files) {
202       if (f.getMediaType().equals("application/clustal")) {
203         return new FormatAdapter().readFile(
204                 f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Clustal);
205       }
206       else if (f.getMediaType().equals("application/fasta")) {
207         return new FormatAdapter().readFile(
208                 f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Fasta);
209       }
210     }
211     return null;
212   }
213
214   @Override
215   public String toString() {
216     return String.format("SlivkaWebService[%s]", getName());
217   }
218 }