001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.hdfs.server.namenode;
020    
021    import java.io.IOException;
022    import org.apache.hadoop.classification.InterfaceAudience;
023    import org.apache.hadoop.classification.InterfaceStability;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    
028    /** Context data for an ongoing NameNode metadata recovery process. */
029    @InterfaceAudience.Private
030    @InterfaceStability.Evolving
031    public final class MetaRecoveryContext  {
032      public static final Log LOG = LogFactory.getLog(MetaRecoveryContext.class.getName());
033      public final static int FORCE_NONE = 0;
034      public final static int FORCE_FIRST_CHOICE = 1;
035      public final static int FORCE_ALL = 2;
036      private int force;
037      
038      /** Exception thrown when the user has requested processing to stop. */
039      static public class RequestStopException extends IOException {
040        private static final long serialVersionUID = 1L;
041        public RequestStopException(String msg) {
042          super(msg);
043        }
044      }
045      
046      public MetaRecoveryContext(int force) {
047        this.force = force;
048      }
049    
050      /**
051       * Display a prompt to the user and get his or her choice.
052       *  
053       * @param prompt      The prompt to display
054       * @param default     First choice (will be taken if autoChooseDefault is
055       *                    true)
056       * @param choices     Other choies
057       *
058       * @return            The choice that was taken
059       * @throws IOException
060       */
061      public String ask(String prompt, String firstChoice, String... choices) 
062          throws IOException {
063        while (true) {
064          LOG.info(prompt);
065          if (force > FORCE_NONE) {
066            LOG.info("automatically choosing " + firstChoice);
067            return firstChoice;
068          }
069          StringBuilder responseBuilder = new StringBuilder();
070          while (true) {
071            int c = System.in.read();
072            if (c == -1 || c == '\r' || c == '\n') {
073              break;
074            }
075            responseBuilder.append((char)c);
076          }
077          String response = responseBuilder.toString();
078          if (response.equalsIgnoreCase(firstChoice))
079            return firstChoice;
080          for (String c : choices) {
081            if (response.equalsIgnoreCase(c)) {
082              return c;
083            }
084          }
085          LOG.error("I'm sorry, I cannot understand your response.\n");
086        }
087      }
088    
089      public static void editLogLoaderPrompt(String prompt,
090            MetaRecoveryContext recovery, String contStr)
091            throws IOException, RequestStopException
092      {
093        if (recovery == null) {
094          throw new IOException(prompt);
095        }
096        LOG.error(prompt);
097        String answer = recovery.ask("\nEnter 'c' to continue, " + contStr + "\n" +
098          "Enter 's' to stop reading the edit log here, abandoning any later " +
099            "edits\n" +
100          "Enter 'q' to quit without saving\n" +
101          "Enter 'a' to always select the first choice in the future " +
102          "without prompting. " + 
103          "(c/s/q/a)\n", "c", "s", "q", "a");
104        if (answer.equals("c")) {
105          LOG.info("Continuing");
106          return;
107        } else if (answer.equals("s")) {
108          throw new RequestStopException("user requested stop");
109        } else if (answer.equals("q")) {
110          recovery.quit();
111        } else {
112          recovery.setForce(FORCE_FIRST_CHOICE);
113          return;
114        }
115      }
116    
117      /** Log a message and quit */
118      public void quit() {
119        LOG.error("Exiting on user request.");
120        System.exit(0);
121      }
122    
123      public int getForce() {
124        return this.force;
125      }
126    
127      public void setForce(int force) {
128        this.force = force;
129      }
130    }