a5c809faff8041b3c6a1aa9b6eec2abd8ee567d6
[jalview.git] / src / jalview / ws / slivkaws / SlivkaWSInstance.java
1 package jalview.ws.slivkaws;
2
3 import jalview.gui.WebserviceInfo;
4 import jalview.ws.api.JalviewServiceEndpointProviderI;
5 import jalview.ws.api.JalviewWebServiceI;
6 import jalview.ws.api.ServiceWithParameters;
7 import jalview.ws.gui.WsJob;
8 import jalview.ws.params.ParamDatastoreI;
9 import jalview.ws.params.ParamManager;
10
11 import java.io.IOError;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.InputStreamReader;
15 import java.util.Arrays;
16 import java.util.EnumMap;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Optional;
20 import java.util.Set;
21
22 import uk.ac.dundee.compbio.slivkaclient.FormValidationException;
23 import uk.ac.dundee.compbio.slivkaclient.JobState;
24 import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
25 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
26 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
27 import uk.ac.dundee.compbio.slivkaclient.ValidationException;
28
29 public abstract class SlivkaWSInstance extends ServiceWithParameters
30     implements JalviewServiceEndpointProviderI, JalviewWebServiceI
31 {
32   protected final SlivkaClient client;
33
34   protected final SlivkaService service;
35
36   protected SlivkaDatastore store = null;
37
38   protected static final EnumMap<JobState, WsJob.JobState> stateMap = new EnumMap<>(JobState.class);
39   {
40     stateMap.put(JobState.PENDING, WsJob.JobState.QUEUED);
41     stateMap.put(JobState.QUEUED, WsJob.JobState.QUEUED);
42     stateMap.put(JobState.RUNNING, WsJob.JobState.RUNNING);
43     stateMap.put(JobState.COMPLETED, WsJob.JobState.FINISHED);
44     stateMap.put(JobState.FAILED, WsJob.JobState.FAILED);
45     stateMap.put(JobState.ERROR, WsJob.JobState.SERVERERROR);
46     stateMap.put(JobState.UNKNOWN, WsJob.JobState.UNKNOWN);
47   }
48   protected final Set<WsJob.JobState> failedStates = new HashSet<>(Arrays.asList(
49       WsJob.JobState.INVALID, WsJob.JobState.BROKEN, WsJob.JobState.FAILED,
50       WsJob.JobState.SERVERERROR, WsJob.JobState.CANCELLED
51   ));
52
53   public SlivkaWSInstance(SlivkaClient client, SlivkaService service, String action)
54   {
55     super(service.getName(), action, service.getLabel(), "Slivka", client.getUrl().toString());
56     this.client = client;
57     this.service = service;
58   }
59
60   @Override
61   public final void updateStatus(WsJob job)
62   {
63     try
64     {
65       job.setState(stateMap.get(client.getJobState(job.getJobId())));
66     } catch (IOException e)
67     {
68       throw new IOError(e);
69     }
70   }
71
72   @Override
73   public final boolean updateJobProgress(WsJob job) throws IOException
74   {
75     List<RemoteFile> files = client.getJobResults(job.getJobId());
76     Optional<RemoteFile> logFile = files.stream()
77         .filter(f -> f.getLabel().equals("log")).findFirst();
78     boolean newContent = false;
79     if (logFile.isPresent())
80     {
81       InputStream stream = logFile.get().getContent();
82       long nextChunk = stream.skip(job.getNextChunk());
83       int len = appendJobStatus(job, stream);
84       job.setnextChunk(nextChunk + len);
85       newContent |= len > 0;
86     }
87     if (failedStates.contains(job.getJobState()))
88     {
89       Optional<RemoteFile> errLogFile = files.stream()
90           .filter(f -> f.getLabel().equals("error-log")).findFirst();
91       if (errLogFile.isPresent())
92       {
93         newContent |= appendJobStatus(job, errLogFile.get().getContent()) > 0;
94       }
95     }
96     return newContent;
97   }
98
99   private int appendJobStatus(WsJob job, InputStream stream) throws IOException
100   {
101     StringBuilder builder = new StringBuilder(job.getStatus());
102     InputStreamReader reader = new InputStreamReader(stream);
103     char[] buffer = new char[4096];
104     int chunkLen = 0;
105     int len = 0;
106     while ((len = reader.read(buffer)) != -1)
107     {
108       chunkLen += len;
109       builder.append(buffer, 0, len);
110     }
111     job.setStatus(builder.toString());
112     return chunkLen;
113   }
114
115   @Override
116   public final boolean handleSubmitError(Throwable _lex, WsJob j, WebserviceInfo wsInfo)
117   {
118     if (_lex instanceof FormValidationException)
119     {
120       FormValidationException formError = (FormValidationException) _lex;
121       String[] messages = new String[formError.getErrors().size()];
122       int i = 0;
123       for (ValidationException e : formError.getErrors())
124       {
125         messages[i++] = String.format("%s: %s,", e.getField().getName(), e.getMessage());
126       }
127       j.setState(WsJob.JobState.INVALID);
128       j.setStatus(String.join(", ", messages));
129       return true;
130     }
131     return false;
132   }
133
134   @Override
135   public final boolean handleCollectionException(Exception e, WsJob msjob, WebserviceInfo wsInfo)
136   {
137     // TODO
138     return false;
139   }
140
141   final SlivkaService getService()
142   {
143     return service;
144   }
145
146   @Override
147   public final Object getEndpoint()
148   {
149     return this;
150   }
151
152   @Override
153   public final void initParamStore(ParamManager userParameterStore)
154   {
155     if (store == null)
156     {
157       try
158       {
159         store = new SlivkaDatastore(service);
160       } catch (IOException e)
161       {
162         throw new IOError(e);
163       }
164     }
165   }
166
167   @Override
168   public boolean hasParameters()
169   {
170     return true;
171   }
172
173   @Override
174   public final ParamDatastoreI getParamStore()
175   {
176     if (store == null)
177     {
178       initParamStore(null);
179     }
180     return store;
181   }
182
183 }