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