81497ab5eac4b28b598efdc9bebf6e0ce53f11c9
[jalview.git] / src / jalview / ext / cipres / CipresExample.java
1 package jalview.ext.cipres;
2
3 /**
4  *  Example originally from cipres_java_client (Example.java there)
5  */
6 import java.io.Console;
7 import java.io.File;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.Map;
15
16 import org.ngbw.directclient.CiApplication;
17 import org.ngbw.directclient.CiCipresException;
18 import org.ngbw.directclient.CiClient;
19 import org.ngbw.directclient.CiJob;
20 import org.ngbw.directclient.CiResultFile;
21 import org.ngbw.directclient.example.Example;
22 import org.ngbw.restdatatypes.ErrorData;
23 import org.ngbw.restdatatypes.LimitStatus;
24 import org.ngbw.restdatatypes.ParamError;
25 import org.ngbw.restdatatypes.StatusData;
26 import org.ngbw.restdatatypes.ToolData;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Example command line application that shows how to use the CIPRES REST API
32  * Java Client library, i.e. the classes in the org.ngbw.directclient package.
33  * By default the example uses DIRECT authentication, but if invoked with the
34  * "-u" command line argument it switches to UMBRELLA authentication. Username,
35  * password, application name and application ID are read from ~/pycipres.conf
36  * and the information in pycipres.conf must correspond to an application
37  * registered for UMBRELLA auth or DIRECT auth respectively depending on whether
38  * you run the example with or with "-u".
39  * <p>
40  * This example repeatedly prompts the user to submit a job, list the user's
41  * already submitted jobs, retrieve a job's status, download a job's results,
42  * delete a job or quit. The example only submits one type of job: clustalw, run
43  * on the included sequence file. Consult the Users Guide for information about
44  * how to configure different kinds of jobs.
45  * <p>
46  * The gist of using the library is that you instantiate a CIClient object, then
47  * use its methods, and the objects that those methods return. When using direct
48  * auth a single CIClient can be used, but when using UMBRELLA auth, a CIClient
49  * must be instantiated for each end user. A CIClient object should not be used
50  * from multiple threads at the same time.
51  * <p>
52  */
53 public class CipresExample
54 {
55   @SuppressWarnings("unused")
56   private static final Logger log = LoggerFactory
57           .getLogger(Example.class.getName());
58
59   private static Console console = System.console();
60
61   private static String entry;
62
63   private static CiClient myClient;
64
65   private static String fastaFile;
66
67   private static boolean umbrella = false;
68
69   // For umbrella app's only
70   private static CiClient adminClient;
71
72   public static void main(String[] args) throws Exception
73   {
74     if (console == null)
75     {
76       System.out.println("No console");
77       return;
78     }
79
80     // If true, the example will use umbrella authentication
81     if (args.length > 0 && args[0].equals("-u"))
82     {
83       umbrella = true;
84     }
85
86     // Copy example fasta file from jar to temp file on disk
87     fastaFile = copyResource("ex1.fasta");
88
89     // Get username, password, app name, app id, url from pycipes.conf
90     CiApplication app = CiApplication.getInstance();
91
92     if (umbrella)
93     {
94       myClient = loginUser(app);
95       if (myClient == null)
96       {
97         return;
98       }
99       adminClient = new CiClient(app.getAppKey(), app.getUsername(),
100               app.getPassword(), app.getRestUrl());
101     }
102     else
103     {
104       myClient = new CiClient(app.getAppKey(), app.getUsername(),
105               app.getPassword(), app.getRestUrl());
106     }
107     String command = "";
108     while (!command.equals("q"))
109     {
110       if (umbrella)
111       {
112         System.out.println(
113                 "\nEnter s(submit), v(validate), l(list), d(delete), j(job status), r(retrieve results), t(show tools), u(change end user) or q(quit):");
114       }
115       else
116       {
117         System.out.println(
118                 "\nEnter s(submit), v(validate), l(list), d(delete), j(job status), r(retrieve results) or t(show tools) or q(quit):");
119       }
120       command = console.readLine();
121       try
122       {
123         if (command.equals("q"))
124         {
125           continue;
126         }
127         if (command.equals("v"))
128         {
129           validateJob();
130         }
131         else if (command.equals("s"))
132         {
133           submitJob();
134         }
135         else if (command.equals("l"))
136         {
137           listJobs();
138         }
139         else if (command.equals("d"))
140         {
141           deleteJob();
142         }
143         else if (command.equals("j"))
144         {
145           jobStatus();
146         }
147         else if (command.equals("r"))
148         {
149           retrieveResults();
150         }
151         else if (umbrella && command.equals("u"))
152         {
153           myClient = loginUser(app);
154           if (myClient == null)
155           {
156             break;
157           }
158         }
159         else if (command.equals("t"))
160         {
161           showTools();
162         }
163         else
164         {
165           System.out.println("invalid response: " + command);
166         }
167       } catch (CiCipresException ce)
168       {
169         ErrorData ed = ce.getErrorData();
170         System.out.println("Cipres error code=" + ed.code + ", message="
171                 + ed.displayMessage);
172         if (ed.code == ErrorData.FORM_VALIDATION)
173         {
174           for (ParamError pe : ed.paramError)
175           {
176             System.out.println(pe.param + ": " + pe.error);
177           }
178         }
179         else if (ed.code == ErrorData.USAGE_LIMIT)
180         {
181           LimitStatus ls = ed.limitStatus;
182           System.out.println("Usage Limit Error, type=" + ls.type
183                   + ", ceiling=" + ls.ceiling);
184         }
185       } catch (Exception e)
186       {
187         System.out.println(e.toString());
188       }
189     }
190   }
191
192   private static void showTools() throws CiCipresException
193   {
194     Collection<ToolData> tools = myClient.listTools();
195     System.out.println("");
196     for (ToolData td : tools)
197     {
198       System.out.println(td.toolId + " : " + td.toolName);
199     }
200   }
201
202   private static void validateJob() throws CiCipresException
203   {
204     System.out.println("Sending a canned clustalw job for validation ...");
205     sendCannedJob("fakeName", true);
206   }
207
208   private static void submitJob() throws CiCipresException
209   {
210     System.out.println(
211             "Will submit an example clustalw job.  Enter a name for the job or enter a single 'n' to cancel");
212     entry = console.readLine();
213     if (entry.equals("n"))
214     {
215       return;
216     }
217     sendCannedJob(entry, false);
218   }
219
220   private static void sendCannedJob(String jobName, boolean validateOnly)
221           throws CiCipresException
222   {
223     Map<String, Collection<String>> vParams = new HashMap<>();
224     HashMap<String, String> inputParams = new HashMap<>();
225     HashMap<String, String> metadata = new HashMap<>();
226
227     vParams.put("runtime_", Arrays.asList(".2"));
228     vParams.put("hgapresidues_", Arrays.asList("A", "D"));
229     inputParams.put("infile_", fastaFile);
230
231     // See https://www.phylo.org/restusers/docs/guide.html#UseOptionalMetadata
232     // for list of available
233     // metadata keys.
234     metadata.put("statusEmail", "true");
235     metadata.put("clientJobName", jobName);
236
237     CiJob jobStatus;
238     if (validateOnly)
239     {
240       jobStatus = myClient.validateJob("CLUSTALW", vParams, inputParams,
241               metadata);
242     }
243     else
244     {
245       jobStatus = myClient.submitJob("CLUSTALW", vParams, inputParams,
246               metadata);
247     }
248     jobStatus.show(true);
249   }
250
251   private static void listJobs() throws CiCipresException
252   {
253
254     int count = 0;
255     Collection<CiJob> jobs = myClient.listJobs();
256     for (CiJob job : jobs)
257     {
258       count += 1;
259       System.out.print("\n" + count + ". ");
260       job.show(false);
261     }
262   }
263
264   private static void deleteJob() throws CiCipresException
265   {
266     System.out.println("Enter url of job to delete or n(no, cancel)");
267     entry = console.readLine();
268     if (!entry.startsWith("http"))
269     {
270       return;
271     }
272     CiJob job = myClient.getJob(entry);
273     job.delete();
274   }
275
276   private static void retrieveResults()
277           throws CiCipresException, IOException
278         {
279     boolean finalResults = true;
280     System.out.println("Enter url of job or n(no, cancel)");
281     entry = console.readLine();
282     if (!entry.startsWith("http"))
283     {
284       return;
285     }
286     CiJob job = myClient.getJob(entry);
287     if (job.isDone() == false)
288     {
289       System.out.println(
290               "Job is not finished. Enter y(yes, get working dir contents) or n(no, cancel)");
291       entry = console.readLine();
292       if (entry.equals("n"))
293       {
294         return;
295       }
296       else
297       {
298         finalResults = false;
299       }
300     }
301     Collection<CiResultFile> files = job.listResults(finalResults);
302     int count = 0;
303     for (CiResultFile file : files)
304     {
305       count = count + 1;
306       System.out.println(count + ". " + file.getName() + " ("
307               + file.getLength() + " bytes )");
308     }
309     System.out.println(
310             "Enter name of file to download or a(all) or n(no, cancel)");
311     entry = console.readLine();
312     boolean all = false;
313     if (entry.equals("a"))
314     {
315       all = true;
316     }
317     else if (entry.equals("n"))
318     {
319       return;
320     }
321     File directory = new File(new File("."), job.getJobHandle());
322     if (!directory.exists())
323     {
324       directory.mkdir();
325     }
326     for (CiResultFile file : files)
327     {
328       if (all == true || file.getName().equals(entry))
329       {
330         System.out.println("Downloading " + file.getName() + " to "
331                 + directory.getAbsolutePath());
332         file.download(directory);
333       }
334     }
335         }
336
337   private static void jobStatus() throws CiCipresException
338         {
339     if (!umbrella)
340     {
341       System.out.println("Enter jobhandle or n(no, cancel)");
342       entry = console.readLine();
343       if (!entry.startsWith("NGBW"))
344       {
345         return;
346       }
347       CiJob job = myClient.getJobFromHandle(entry);
348       job.show(true);
349     }
350     else
351     {
352       /*
353               This shows how an umbrella app can get status of multiple jobs for multiple users in
354               a single call.  This is the only thing an umbrella app can do with a CiClient (see
355               adminClient below) that is configured without endUserHeaders.  Everything else must
356               be done for a specific end user with a CiClient configured for that user.
357               
358               An Umbrella app could also use the code above (in the !umbrella case) to get status of a 
359               single job, using a CiClient configured for the owner of the job. 
360       
361       */
362       System.out.println(
363               "Enter comma separated list of jobhandles or n(no, cancel)");
364       entry = console.readLine();
365       if (!entry.startsWith("NGBW"))
366       {
367         return;
368       }
369       String[] handles = entry.split(",");
370       ArrayList<String> handleList = new ArrayList<>(handles.length);
371       for (String handle : handles)
372       {
373         handleList.add(handle.trim());
374       }
375       // Collection<StatusData> jobList =
376       // adminClient.getMultipleJobStatus(handleList);
377       Collection<StatusData> jobList = myClient
378               .getMultipleJobStatus(handleList);
379       System.out.println("\n");
380       for (StatusData jobstatus : jobList)
381       {
382         String str = jobstatus.jobHandle + " ";
383         if (jobstatus.terminalStage == true)
384         {
385           if (jobstatus.failed == true)
386           {
387             str += " failed at stage " + jobstatus.jobStage;
388           }
389           else
390           {
391             str += " finished, results at " + jobstatus.resultsUri.url;
392           }
393         }
394         else
395         {
396           str += " is not finished, stage = " + jobstatus.jobStage;
397         }
398         System.out.println(str);
399       }
400     }
401         }
402
403   private static String copyResource(String name) throws IOException
404   {
405     InputStream is;
406
407     is = Example.class.getResourceAsStream("/" + name);
408     File dest = File.createTempFile("Example", ".txt");
409     dest.deleteOnExit();
410
411     CiResultFile.copyInputStreamToFile(is, dest);
412     return dest.getAbsolutePath();
413   }
414
415   private static CiClient loginUser(CiApplication app) throws Exception
416   {
417     Map<String, String> endUserHeaders = new HashMap<>();
418
419     System.out.println(
420             "\nEnter information about the current end user of this application.");
421     System.out.println("Enter username or q(quit)");
422     String username = console.readLine();
423     if (username.equals("q"))
424     {
425       return null;
426     }
427     System.out.println("Enter user's email address or q(quit)");
428     String email = console.readLine();
429     if (email.equals("q"))
430     {
431       return null;
432     }
433     System.out.println("Enter user's institution or q(quit)");
434     String institution = console.readLine();
435     if (institution.equals("q"))
436     {
437       return null;
438     }
439     System.out.println(
440             "Enter user's country code (must be 2 letters, both uppercase) or q(quit)");
441     String country = console.readLine();
442     if (country.equals("q"))
443     {
444       return null;
445     }
446     endUserHeaders.put("cipres-eu", username.trim());
447     endUserHeaders.put("cipres-eu-email", email.trim());
448     endUserHeaders.put("cipres-eu-institution", institution.trim());
449     endUserHeaders.put("cipres-eu-country", country.trim());
450     endUserHeaders.put("cipres-eu-email", email.trim());
451
452     log.debug(
453             "cipres-eu-email is " + endUserHeaders.get("cipres-eu-email"));
454     myClient = new CiClient(app.getAppKey(), app.getAppname(),
455             app.getUsername(), app.getPassword(), app.getRestUrl(),
456             endUserHeaders);
457     return myClient;
458   }
459
460 }
461