001package co.codewizards.cloudstore.client; 002 003import java.io.Console; 004 005import co.codewizards.cloudstore.ls.rest.client.LocalServerRestClient; 006import co.codewizards.cloudstore.ls.server.LocalServer; 007 008/** 009 * <p> 010 * Sub-command for a certain CLI operation. 011 * <p> 012 * The CloudStore-command-line-interface uses a syntax similar to the svn command and the logic of the 013 * command 'java -jar co.codewizards.cloudstore.client-VERSION.jar SUBCOMMAND -arg1 val1 -arg2 val2 ...' 014 * is thus actually implemented by a class extending this class and {@link #getSubCommandName() registering} 015 * for a certain 'SUBCOMMAND'. 016 * <p> 017 * Every subclass of this class can declare its arguments using annotations like {@link Option}. 018 * 019 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 020 */ 021public abstract class SubCommand 022{ 023 private String subCommandName; 024 025 private LocalServer localServer; 026 027 /** 028 * Get the name of the sub-command, i.e. what the user has to write in the command line. 029 * @return the name of the sub-command. 030 */ 031 public String getSubCommandName() { 032 if (subCommandName == null) { 033 final String suffix = "SubCommand"; 034 String simpleName = this.getClass().getSimpleName(); 035 if (!simpleName.endsWith(suffix)) 036 throw new IllegalStateException( 037 String.format("Class name '%s' does not end with suffix '%s'! Rename the class or override the 'getSubCommand()' method!", 038 simpleName, suffix)); 039 040 StringBuilder sb = new StringBuilder(); 041 sb.append(simpleName.substring(0, simpleName.length() - suffix.length())); 042 if (sb.length() == 0) 043 throw new IllegalStateException( 044 String.format("Class name '%s' equals suffix '%s'! There should be sth. before the suffix! Rename the class or override the 'getSubCommand()' method!", 045 simpleName, suffix)); 046 047 sb.setCharAt(0, Character.toLowerCase(sb.charAt(0))); 048 subCommandName = sb.toString(); 049 } 050 return subCommandName; 051 } 052 053 /** 054 * Get the description for this sub-command. 055 * @return the description. 056 */ 057 public abstract String getSubCommandDescription(); 058 059 /** 060 * Invoked before {@link #run()}. 061 * <p> 062 * Implementors should always invoked the super-method when overriding! 063 * @throws Exception in case, the preparation failed. 064 * @see #cleanUp() 065 */ 066 public void prepare() throws Exception { 067 localServer = new LocalServer(); 068 if (! localServer.start()) 069 localServer = null; 070 } 071 072 public abstract void run() 073 throws Exception; 074 075 /** 076 * Invoked after {@link #run()}. 077 * <p> 078 * This method is always invoked, when {@link #prepare()} was invoked - even if {@link #run()} failed with an exception. 079 * <p> 080 * Implementors should always invoked the super-method when overriding (preferably at the end)! 081 * @throws Exception in case, cleaning up failed. 082 * @see #prepare() 083 */ 084 public void cleanUp() throws Exception { 085 if (localServer != null) { 086 localServer.stop(); 087 localServer = null; 088 } 089 } 090 091 protected String promptPassword(String fmt, Object ... args) { 092 Console console = System.console(); 093 if (console == null) 094 throw new IllegalStateException("There is no system console! Cannot prompt \"" + String.format(fmt, args) + "\"!!!"); 095 096 char[] pw = console.readPassword(fmt, args); 097 if (pw == null) 098 return null; 099 else 100 return new String(pw); 101 } 102 103 protected String prompt(String fmt, Object ... args) { 104 Console console = System.console(); 105 if (console == null) 106 throw new IllegalStateException("There is no system console! Cannot prompt \"" + String.format(fmt, args) + "\"!!!"); 107 108 String result = console.readLine(fmt, args); 109 return result; 110 } 111 112 public boolean isVisibleInHelp() { 113 return true; 114 } 115 116 public LocalServerRestClient getLocalServerRestClient() { 117 return LocalServerRestClient.getInstance(); 118 } 119}