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}