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
019package org.apache.hadoop.hdfs.server.namenode;
020
021import java.io.IOException;
022import org.apache.hadoop.classification.InterfaceAudience;
023import org.apache.hadoop.classification.InterfaceStability;
024
025import org.apache.commons.logging.Log;
026import org.apache.commons.logging.LogFactory;
027
028/** Context data for an ongoing NameNode metadata recovery process. */
029@InterfaceAudience.Private
030@InterfaceStability.Evolving
031public 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      System.err.print(prompt);
065      if (force > FORCE_NONE) {
066        System.out.println("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      System.err.print("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}