a3aa22680202fa93dc59f3efdd8d7e3496f32d44
[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 getName() { return service.getName(); }
77
78   @Override
79   public String getDescription() { return service.getDescription(); }
80
81   @Override
82   public String getOperationType() { return operation; }
83
84   @Override
85   public List<Operation> getOperations() {
86     return operations;
87   }
88
89   void addOperation(Operation operation) {
90     operations.add(operation);
91   }
92
93   void removeOperation(Operation operation) {
94     operations.remove(operation);
95   }
96
97   @Override
98   public boolean hasParameters() {
99     return getParamStore().getServiceParameters().size() > 0;
100   }
101
102   @Override
103   public ParamDatastoreI getParamStore() {
104     if (store == null) {
105       store = new SlivkaDatastore(service);
106     }
107     return store;
108   }
109
110   @Override
111   public WSJob submit(List<SequenceI> sequences, List<ArgumentI> args) throws IOException
112   {
113     var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
114     for (Parameter param : service.getParameters()) {
115       if (param instanceof Parameter.FileParameter) {
116         // if finds a file input, gives it sequences stream
117         Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
118         FileFormat format;
119         switch (fileParam.getMediaType()) {
120         case "application/pfam":
121           format = FileFormat.Pfam;
122           break;
123         case "application/stockholm":
124           format = FileFormat.Stockholm;
125           break;
126         case "application/clustal":
127           format = FileFormat.Clustal;
128           break;
129         case "application/fasta":
130         default:
131           format = FileFormat.Fasta;
132           break;
133         }
134         InputStream stream = new ByteArrayInputStream(
135                 format.getWriter(null)
136                 .print(sequences.toArray(new SequenceI[0]), false)
137                 .getBytes());
138         request.addFile(param.getId(), stream);
139       }
140     }
141     if (args != null) {
142       for (ArgumentI arg : args) {
143         // multiple choice field names are name$number to avoid duplications
144         // the number is stripped here
145         String paramId = arg.getName().split("\\$", 2)[0];
146         Parameter param = service.getParameter(paramId);
147         if (param instanceof Parameter.FlagParameter) {
148           if (arg.getValue() != null && !arg.getValue().isBlank())
149             request.addData(paramId, true);
150           else
151             request.addData(paramId, false);
152         }
153         else
154         {
155           request.addData(paramId, arg.getValue());
156         }
157       }
158     }
159     var job = service.submitJob(request);
160     return new WSJob("slivka", getName(), job.getId(), getHostName());
161   }
162
163   @Override
164   public void updateProgress(WSJob job)
165           throws IOException
166   {
167     // TODO Auto-generated method stub
168
169   }
170
171   @Override
172   public void cancel(WSJob job) throws IOException
173   {
174     Cache.log.warn("Slivka does not support job cancellation yet.");
175   }
176
177   @Override
178   public boolean handleSubmissionError(WSJob job, Exception ex)
179   {
180     if (ex instanceof ClientProtocolException) {
181       Cache.log.error("Job submission failed due to exception.", ex);
182       return true;
183     }
184     return false;
185   }
186
187   @Override
188   public boolean handleCollectionError(WSJob job, Exception ex)
189   {
190     // TODO Auto-generated method stub
191     return false;
192   }
193
194   public AlignmentI getAlignment(WSJob job) throws IOException {
195     Collection<RemoteFile> files;
196     var slivkaJob = client.getJob(job.getJobID());
197     files = slivkaJob.getResults();
198     for (RemoteFile f : files) {
199       if (f.getMediaType().equals("application/clustal")) {
200         return new FormatAdapter().readFile(
201                 f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Clustal);
202       }
203       else if (f.getMediaType().equals("application/fasta")) {
204         return new FormatAdapter().readFile(
205                 f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Fasta);
206       }
207     }
208     return null;
209   }
210
211   @Override
212   public String toString() {
213     return String.format("SlivkaWebService[%s]", getName());
214   }
215 }