c2ac7b3278ea0ffc694beea7b3abfff97de353b6
[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
42   protected final SlivkaService service;
43
44   protected SlivkaDatastore store = null;
45
46   protected final ArrayList<Operation> operations = new ArrayList<>();
47
48   protected int typeFlags = 0;
49
50   protected static final EnumMap<Job.Status, WsJob.JobState> stateMap = new EnumMap<>(
51           Job.Status.class);
52   {
53     stateMap.put(Job.Status.PENDING, WsJob.JobState.QUEUED);
54     stateMap.put(Job.Status.REJECTED, WsJob.JobState.INVALID);
55     stateMap.put(Job.Status.ACCEPTED, WsJob.JobState.QUEUED);
56     stateMap.put(Job.Status.QUEUED, WsJob.JobState.QUEUED);
57     stateMap.put(Job.Status.RUNNING, WsJob.JobState.RUNNING);
58     stateMap.put(Job.Status.COMPLETED, WsJob.JobState.FINISHED);
59     stateMap.put(Job.Status.INTERRUPTED, WsJob.JobState.CANCELLED);
60     stateMap.put(Job.Status.DELETED, WsJob.JobState.CANCELLED);
61     stateMap.put(Job.Status.FAILED, WsJob.JobState.FAILED);
62     stateMap.put(Job.Status.ERROR, WsJob.JobState.SERVERERROR);
63     stateMap.put(Job.Status.UNKNOWN, WsJob.JobState.UNKNOWN);
64   }
65
66   protected final Set<WsJob.JobState> failedStates = new HashSet<>(
67           Arrays.asList(WsJob.JobState.INVALID, WsJob.JobState.BROKEN,
68                   WsJob.JobState.FAILED, WsJob.JobState.SERVERERROR,
69                   WsJob.JobState.CANCELLED));
70
71   public SlivkaWebService(SlivkaClient client, SlivkaService service)
72   {
73     this.client = client;
74     this.service = service;
75   }
76
77   @Override
78   public String getHostName()
79   {
80     return client.getUrl().toString();
81   }
82
83   @Override
84   public String getProviderName()
85   {
86     return "slivka";
87   }
88
89   @Override
90   public String getName()
91   {
92     return service.getName();
93   }
94
95   @Override
96   public String getDescription()
97   {
98     return service.getDescription();
99   }
100
101   @Override
102   public List<Operation> getOperations()
103   {
104     return operations;
105   }
106
107   void addOperation(Operation operation)
108   {
109     operations.add(operation);
110   }
111
112   void removeOperation(Operation operation)
113   {
114     operations.remove(operation);
115   }
116
117   @Override
118   public boolean hasParameters()
119   {
120     return getParamStore().getServiceParameters().size() > 0;
121   }
122
123   @Override
124   public ParamDatastoreI getParamStore()
125   {
126     if (store == null)
127     {
128       store = new SlivkaDatastore(service);
129     }
130     return store;
131   }
132
133   @Override
134   public String submit(List<SequenceI> sequences, List<ArgumentI> args)
135           throws IOException
136   {
137     var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
138     for (Parameter param : service.getParameters())
139     {
140       if (param instanceof Parameter.FileParameter)
141       {
142         // if finds a file input, gives it sequences stream
143         Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
144         FileFormat format;
145         switch (fileParam.getMediaType())
146         {
147         case "application/pfam":
148           format = FileFormat.Pfam;
149           break;
150         case "application/stockholm":
151           format = FileFormat.Stockholm;
152           break;
153         case "application/clustal":
154           format = FileFormat.Clustal;
155           break;
156         case "application/fasta":
157         default:
158           format = FileFormat.Fasta;
159           break;
160         }
161         InputStream stream = new ByteArrayInputStream(format.getWriter(null)
162                 .print(sequences.toArray(new SequenceI[0]), false)
163                 .getBytes());
164         request.addFile(param.getId(), stream);
165       }
166     }
167     if (args != null)
168     {
169       for (ArgumentI arg : args)
170       {
171         // multiple choice field names are name$number to avoid duplications
172         // the number is stripped here
173         String paramId = arg.getName().split("\\$", 2)[0];
174         Parameter param = service.getParameter(paramId);
175         if (param instanceof Parameter.FlagParameter)
176         {
177           if (arg.getValue() != null && !arg.getValue().isBlank())
178             request.addData(paramId, true);
179           else
180             request.addData(paramId, false);
181         }
182         else
183         {
184           request.addData(paramId, arg.getValue());
185         }
186       }
187     }
188     var job = service.submitJob(request);
189     return job.getId();
190   }
191
192   @Override
193   public void updateProgress(WSJob job) throws IOException
194   {
195     // TODO Auto-generated method stub
196
197   }
198
199   @Override
200   public void cancel(WSJob job) throws IOException
201   {
202     Cache.log.warn("Slivka does not support job cancellation yet.");
203   }
204
205   @Override
206   public boolean handleSubmissionError(WSJob job, Exception ex)
207   {
208     if (ex instanceof ClientProtocolException)
209     {
210       Cache.log.error("Job submission failed due to exception.", ex);
211       return true;
212     }
213     return false;
214   }
215
216   @Override
217   public boolean handleCollectionError(WSJob job, Exception ex)
218   {
219     // TODO Auto-generated method stub
220     return false;
221   }
222
223   public AlignmentI getAlignment(WSJob job) throws IOException
224   {
225     Collection<RemoteFile> files;
226     var slivkaJob = client.getJob(job.getJobId());
227     files = slivkaJob.getResults();
228     for (RemoteFile f : files)
229     {
230       if (f.getMediaType().equals("application/clustal"))
231       {
232         return new FormatAdapter().readFile(f.getContentUrl().toString(),
233                 DataSourceType.URL, FileFormat.Clustal);
234       }
235       else if (f.getMediaType().equals("application/fasta"))
236       {
237         return new FormatAdapter().readFile(f.getContentUrl().toString(),
238                 DataSourceType.URL, FileFormat.Fasta);
239       }
240     }
241     return null;
242   }
243
244   @Override
245   public String toString()
246   {
247     return String.format("SlivkaWebService[%s]", getName());
248   }
249 }