This is an automated email from the ASF dual-hosted git repository.

brfrn169 pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2 by this push:
     new 2a63d46  HBASE-24776 [hbtop] Support Batch mode (#2291)
2a63d46 is described below

commit 2a63d467f4b2cceb37786dbbb756a6091b69695b
Author: Toshihiro Suzuki <brfrn...@gmail.com>
AuthorDate: Thu Sep 10 17:04:57 2020 +0900

    HBASE-24776 [hbtop] Support Batch mode (#2291)
    
    Signed-off-by: stack <st...@apache.org>
---
 .../java/org/apache/hadoop/hbase/hbtop/HBTop.java  | 164 +++++++++++++++++----
 .../hbase/hbtop/screen/AbstractScreenView.java     |   1 +
 .../apache/hadoop/hbase/hbtop/screen/Screen.java   |  26 +++-
 .../hbase/hbtop/screen/top/TopScreenModel.java     |  49 ++++--
 .../hbase/hbtop/screen/top/TopScreenPresenter.java |  48 ++++--
 .../hbase/hbtop/screen/top/TopScreenView.java      |  48 ++++--
 .../hadoop/hbase/hbtop/terminal/Terminal.java      |   2 +-
 .../hbtop/terminal/impl/batch/BatchTerminal.java   |  80 ++++++++++
 .../batch/BatchTerminalPrinter.java}               |  51 ++++---
 .../hbase/hbtop/screen/top/TestTopScreenModel.java |  16 +-
 .../hbtop/screen/top/TestTopScreenPresenter.java   |   3 +-
 11 files changed, 390 insertions(+), 98 deletions(-)

diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java
index 34c83f5..9c1a000 100644
--- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java
+++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java
@@ -17,11 +17,17 @@
  */
 package org.apache.hadoop.hbase.hbtop;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configured;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
+import org.apache.hadoop.hbase.hbtop.field.Field;
+import org.apache.hadoop.hbase.hbtop.field.FieldInfo;
 import org.apache.hadoop.hbase.hbtop.mode.Mode;
 import org.apache.hadoop.hbase.hbtop.screen.Screen;
 import org.apache.hadoop.util.Tool;
@@ -56,17 +62,14 @@ public class HBTop extends Configured implements Tool {
   public int run(String[] args) throws Exception {
     long initialRefreshDelay = 3 * 1000;
     Mode initialMode = Mode.REGION;
+    List<Field> initialFields = null;
+    Field initialSortField = null;
+    Boolean initialAscendingSort = null;
+    List<RecordFilter> initialFilters = null;
+    long numberOfIterations = Long.MAX_VALUE;
+    boolean batchMode = false;
     try {
-      // Command line options
-      Options opts = new Options();
-      opts.addOption("h", "help", false,
-        "Print usage; for help while the tool is running press 'h'");
-      opts.addOption("d", "delay", true,
-        "The refresh delay (in seconds); default is 3 seconds");
-      opts.addOption("m", "mode", true,
-        "The mode; n (Namespace)|t (Table)|r (Region)|s (RegionServer)"
-          + ", default is r (Region)");
-
+      Options opts = getOptions();
       CommandLine commandLine = new DefaultParser().parse(opts, args);
 
       if (commandLine.hasOption("help")) {
@@ -74,20 +77,6 @@ public class HBTop extends Configured implements Tool {
         return 0;
       }
 
-      if (commandLine.hasOption("delay")) {
-        int delay = 0;
-        try {
-          delay = Integer.parseInt(commandLine.getOptionValue("delay"));
-        } catch (NumberFormatException ignored) {
-        }
-
-        if (delay < 1) {
-          LOGGER.warn("Delay set too low or invalid, using default");
-        } else {
-          initialRefreshDelay = delay * 1000L;
-        }
-      }
-
       if (commandLine.hasOption("mode")) {
         String mode = commandLine.getOptionValue("mode");
         switch (mode) {
@@ -107,23 +96,148 @@ public class HBTop extends Configured implements Tool {
             initialMode = Mode.REGION_SERVER;
             break;
 
+          case "u":
+            initialMode = Mode.USER;
+            break;
+
+          case "c":
+            initialMode = Mode.CLIENT;
+            break;
+
           default:
             LOGGER.warn("Mode set invalid, using default");
             break;
         }
       }
+
+      if (commandLine.hasOption("outputFieldNames")) {
+        initialMode.getFieldInfos().forEach(f -> 
System.out.println(f.getField().getHeader()));
+        return 0;
+      }
+
+      if (commandLine.hasOption("delay")) {
+        int delay = 0;
+        try {
+          delay = Integer.parseInt(commandLine.getOptionValue("delay"));
+        } catch (NumberFormatException ignored) {
+        }
+
+        if (delay < 1) {
+          LOGGER.warn("Delay set too low or invalid, using default");
+        } else {
+          initialRefreshDelay = delay * 1000L;
+        }
+      }
+
+      if (commandLine.hasOption("numberOfIterations")) {
+        try {
+          numberOfIterations = 
Long.parseLong(commandLine.getOptionValue("numberOfIterations"));
+        } catch (NumberFormatException ignored) {
+          LOGGER.warn("The number of iterations set invalid, ignoring");
+        }
+      }
+
+      if (commandLine.hasOption("sortField")) {
+        String sortField = commandLine.getOptionValue("sortField");
+
+        String field;
+        boolean ascendingSort;
+        if (sortField.startsWith("+")) {
+          field = sortField.substring(1);
+          ascendingSort = false;
+        } else if (sortField.startsWith("-")) {
+          field = sortField.substring(1);
+          ascendingSort = true;
+        } else {
+          field = sortField;
+          ascendingSort = false;
+        }
+
+        Optional<FieldInfo> fieldInfo = initialMode.getFieldInfos().stream()
+          .filter(f -> f.getField().getHeader().equals(field)).findFirst();
+        if (fieldInfo.isPresent()) {
+          initialSortField = fieldInfo.get().getField();
+          initialAscendingSort = ascendingSort;
+        } else {
+          LOGGER.warn("The specified sort field " + field + " is not found, 
using default");
+        }
+      }
+
+      if (commandLine.hasOption("fields")) {
+        String[] fields = commandLine.getOptionValue("fields").split(",");
+        initialFields = new ArrayList<>();
+        for (String field : fields) {
+          Optional<FieldInfo> fieldInfo = initialMode.getFieldInfos().stream()
+            .filter(f -> f.getField().getHeader().equals(field)).findFirst();
+          if (fieldInfo.isPresent()) {
+            initialFields.add(fieldInfo.get().getField());
+          } else {
+            LOGGER.warn("The specified field " + field + " is not found, 
ignoring");
+          }
+        }
+      }
+
+      if (commandLine.hasOption("filters")) {
+        String[] filters = commandLine.getOptionValue("filters").split(",");
+        List<Field> fields = 
initialMode.getFieldInfos().stream().map(FieldInfo::getField)
+          .collect(Collectors.toList());
+        for (String filter : filters) {
+          RecordFilter f = RecordFilter.parse(filter, fields, false);
+          if (f != null) {
+            if (initialFilters == null) {
+              initialFilters = new ArrayList<>();
+            }
+            initialFilters.add(f);
+          } else {
+            LOGGER.warn("The specified filter " + filter + " is invalid, 
ignoring");
+          }
+        }
+      }
+
+      if (commandLine.hasOption("batchMode")) {
+        batchMode = true;
+      }
     } catch (Exception e) {
       LOGGER.error("Unable to parse options", e);
       return 1;
     }
 
-    try (Screen screen = new Screen(getConf(), initialRefreshDelay, 
initialMode)) {
+    try (Screen screen = new Screen(getConf(), initialRefreshDelay, 
initialMode, initialFields,
+      initialSortField, initialAscendingSort, initialFilters, 
numberOfIterations, batchMode)) {
       screen.run();
     }
 
     return 0;
   }
 
+  private Options getOptions() {
+    Options opts = new Options();
+    opts.addOption("h", "help", false,
+      "Print usage; for help while the tool is running press 'h'");
+    opts.addOption("d", "delay", true,
+      "The refresh delay (in seconds); default is 3 seconds");
+    opts.addOption("m", "mode", true,
+      "The mode; n (Namespace)|t (Table)|r (Region)|s (RegionServer)|u (User)"
+        + "|c (Client), default is r");
+    opts.addOption("n", "numberOfIterations", true,
+      "The number of iterations");
+    opts.addOption("s", "sortField", true,
+      "The initial sort field. You can prepend a `+' or `-' to the field name 
to also override"
+        + " the sort direction. A leading `+' will force sorting high to low, 
whereas a `-' will"
+        + " ensure a low to high ordering");
+    opts.addOption("O", "outputFieldNames", false,
+      "Print each of the available field names on a separate line, then quit");
+    opts.addOption("f", "fields", true,
+      "Show only the given fields. Specify comma separated fields to show 
multiple fields");
+    opts.addOption("i", "filters", true,
+      "The initial filters. Specify comma separated filters to set multiple 
filters");
+    opts.addOption("b", "batchMode", false,
+      "Starts hbtop in Batch mode, which could be useful for sending output 
from hbtop to other"
+        + " programs or to a file. In this mode, hbtop will not accept input 
and runs until the"
+        + " iterations limit you've set with the `-n' command-line option or 
until killed");
+    return opts;
+  }
+
   private void printUsage(Options opts) {
     new HelpFormatter().printHelp("hbase hbtop [opts] [-D<property=value>]*", 
opts);
     System.out.println("");
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java
 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java
index cb5520e..8b55d6e 100644
--- 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java
+++ 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java
@@ -75,6 +75,7 @@ public abstract class AbstractScreenView implements 
ScreenView {
     return terminal.getTerminalPrinter(startRow);
   }
 
+  @Nullable
   protected TerminalSize getTerminalSize() {
     return terminal.getSize();
   }
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java
index aa951cf..0301664 100644
--- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java
+++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java
@@ -17,18 +17,23 @@
  */
 package org.apache.hadoop.hbase.hbtop.screen;
 
+import edu.umd.cs.findbugs.annotations.Nullable;
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.client.Connection;
 import org.apache.hadoop.hbase.client.ConnectionFactory;
+import org.apache.hadoop.hbase.hbtop.RecordFilter;
+import org.apache.hadoop.hbase.hbtop.field.Field;
 import org.apache.hadoop.hbase.hbtop.mode.Mode;
 import org.apache.hadoop.hbase.hbtop.screen.top.TopScreenView;
 import org.apache.hadoop.hbase.hbtop.terminal.KeyPress;
 import org.apache.hadoop.hbase.hbtop.terminal.Terminal;
 import org.apache.hadoop.hbase.hbtop.terminal.impl.TerminalImpl;
+import org.apache.hadoop.hbase.hbtop.terminal.impl.batch.BatchTerminal;
 import org.apache.yetus.audience.InterfaceAudience;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,15 +54,23 @@ public class Screen implements Closeable {
   private ScreenView currentScreenView;
   private Long timerTimestamp;
 
-  public Screen(Configuration conf, long initialRefreshDelay, Mode initialMode)
+  public Screen(Configuration conf, long initialRefreshDelay, Mode initialMode,
+    @Nullable List<Field> initialFields, @Nullable Field initialSortField,
+    @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> 
initialFilters,
+    long numberOfIterations, boolean batchMode)
     throws IOException {
     connection = ConnectionFactory.createConnection(conf);
     admin = connection.getAdmin();
 
     // The first screen is the top screen
-    this.terminal = new TerminalImpl("hbtop");
+    if (batchMode) {
+      terminal = new BatchTerminal();
+    } else {
+      terminal = new TerminalImpl("hbtop");
+    }
     currentScreenView = new TopScreenView(this, terminal, initialRefreshDelay, 
admin,
-      initialMode);
+      initialMode, initialFields, initialSortField, initialAscendingSort, 
initialFilters,
+      numberOfIterations);
   }
 
   @Override
@@ -91,11 +104,8 @@ public class Screen implements Closeable {
               timerTimestamp = null;
               nextScreenView = currentScreenView.handleTimer();
             } else {
-              if (timerTimestamp - now < SLEEP_TIMEOUT_MILLISECONDS) {
-                TimeUnit.MILLISECONDS.sleep(timerTimestamp - now);
-              } else {
-                TimeUnit.MILLISECONDS.sleep(SLEEP_TIMEOUT_MILLISECONDS);
-              }
+              TimeUnit.MILLISECONDS
+                .sleep(Math.min(timerTimestamp - now, 
SLEEP_TIMEOUT_MILLISECONDS));
               continue;
             }
           } else {
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java
 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java
index 3dd7f12..bdd52a7 100644
--- 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java
+++ 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java
@@ -19,13 +19,13 @@ package org.apache.hadoop.hbase.hbtop.screen.top;
 
 import static 
org.apache.commons.lang3.time.DateFormatUtils.ISO_8601_EXTENDED_TIME_FORMAT;
 
+import edu.umd.cs.findbugs.annotations.Nullable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
-
 import org.apache.hadoop.hbase.ClusterMetrics;
 import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.hbtop.Record;
@@ -64,28 +64,55 @@ public class TopScreenModel {
 
   private boolean ascendingSort;
 
-  public TopScreenModel(Admin admin, Mode initialMode) {
+  public TopScreenModel(Admin admin, Mode initialMode, @Nullable List<Field> 
initialFields,
+    @Nullable Field initialSortField, @Nullable Boolean initialAscendingSort,
+    @Nullable List<RecordFilter> initialFilters) {
     this.admin = Objects.requireNonNull(admin);
-    switchMode(Objects.requireNonNull(initialMode), null, false);
+    switchMode(Objects.requireNonNull(initialMode), initialSortField, false, 
initialFields,
+      initialAscendingSort, initialFilters);
   }
 
-  public void switchMode(Mode nextMode, List<RecordFilter> initialFilters,
-    boolean keepSortFieldAndSortOrderIfPossible) {
+  public void switchMode(Mode nextMode, boolean 
keepSortFieldAndSortOrderIfPossible,
+    List<RecordFilter> initialFilters) {
+    switchMode(nextMode, null, keepSortFieldAndSortOrderIfPossible, null, 
null, initialFilters);
+  }
 
+  public void switchMode(Mode nextMode, Field initialSortField,
+    boolean keepSortFieldAndSortOrderIfPossible, @Nullable List<Field> 
initialFields,
+    @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> 
initialFilters) {
     currentMode = nextMode;
     fieldInfos = Collections.unmodifiableList(new 
ArrayList<>(currentMode.getFieldInfos()));
-    fields = Collections.unmodifiableList(currentMode.getFieldInfos().stream()
-      .map(FieldInfo::getField).collect(Collectors.toList()));
+
+    if (initialFields != null) {
+      List<Field> tmp = new ArrayList<>(initialFields);
+      tmp.addAll(currentMode.getFieldInfos().stream().map(FieldInfo::getField)
+        .filter(f -> !initialFields.contains(f))
+        .collect(Collectors.toList()));
+      fields = Collections.unmodifiableList(tmp);
+    } else {
+      fields = 
Collections.unmodifiableList(currentMode.getFieldInfos().stream()
+        .map(FieldInfo::getField).collect(Collectors.toList()));
+    }
 
     if (keepSortFieldAndSortOrderIfPossible) {
       boolean match = fields.stream().anyMatch(f -> f == currentSortField);
       if (!match) {
+        if (initialSortField != null && initialAscendingSort != null) {
+          currentSortField = initialSortField;
+          ascendingSort = initialAscendingSort;
+        } else {
+          currentSortField = nextMode.getDefaultSortField();
+          ascendingSort = false;
+        }
+      }
+    } else {
+      if (initialSortField != null && initialAscendingSort != null) {
+        currentSortField = initialSortField;
+        ascendingSort = initialAscendingSort;
+      } else {
         currentSortField = nextMode.getDefaultSortField();
         ascendingSort = false;
       }
-    } else {
-      currentSortField = nextMode.getDefaultSortField();
-      ascendingSort = false;
     }
 
     clearFilters();
@@ -173,7 +200,7 @@ public class TopScreenModel {
     if (drillDownInfo == null) {
       return false;
     }
-    switchMode(drillDownInfo.getNextMode(), drillDownInfo.getInitialFilters(), 
true);
+    switchMode(drillDownInfo.getNextMode(), true, 
drillDownInfo.getInitialFilters());
     return true;
   }
 
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java
 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java
index b22aee0..6fbd23f 100644
--- 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java
+++ 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java
@@ -17,6 +17,7 @@
  */
 package org.apache.hadoop.hbase.hbtop.screen.top;
 
+import edu.umd.cs.findbugs.annotations.Nullable;
 import java.util.ArrayList;
 import java.util.EnumMap;
 import java.util.List;
@@ -57,21 +58,38 @@ public class TopScreenPresenter {
   private final EnumMap<Field, Boolean> fieldDisplayMap = new 
EnumMap<>(Field.class);
   private final EnumMap<Field, Integer> fieldLengthMap = new 
EnumMap<>(Field.class);
 
+  private final long numberOfIterations;
+  private long iterations;
+
   public TopScreenPresenter(TopScreenView topScreenView, long 
initialRefreshDelay,
-    TopScreenModel topScreenModel) {
+    TopScreenModel topScreenModel, @Nullable List<Field> initialFields, long 
numberOfIterations) {
     this.topScreenView = Objects.requireNonNull(topScreenView);
     this.refreshDelay = new AtomicLong(initialRefreshDelay);
     this.topScreenModel = Objects.requireNonNull(topScreenModel);
+    this.numberOfIterations = numberOfIterations;
 
-    initFieldDisplayMapAndFieldLengthMap();
+    initFieldDisplayMapAndFieldLengthMap(initialFields);
   }
 
   public void init() {
-    terminalLength = topScreenView.getTerminalSize().getColumns();
-    paging.updatePageSize(topScreenView.getPageSize());
+    updateTerminalLengthAndPageSize(topScreenView.getTerminalSize(), 
topScreenView.getPageSize());
     topScreenView.hideCursor();
   }
 
+  private void updateTerminalLengthAndPageSize(@Nullable TerminalSize 
terminalSize,
+    @Nullable Integer pageSize) {
+    if (terminalSize != null) {
+      terminalLength = terminalSize.getColumns();
+    } else {
+      terminalLength = Integer.MAX_VALUE;
+    }
+    if (pageSize != null) {
+      paging.updatePageSize(pageSize);
+    } else {
+      paging.updatePageSize(Integer.MAX_VALUE);
+    }
+  }
+
   public long refresh(boolean force) {
     if (!force) {
       long delay = System.currentTimeMillis() - lastRefreshTimestamp;
@@ -82,8 +100,7 @@ public class TopScreenPresenter {
 
     TerminalSize newTerminalSize = topScreenView.doResizeIfNecessary();
     if (newTerminalSize != null) {
-      terminalLength = newTerminalSize.getColumns();
-      paging.updatePageSize(topScreenView.getPageSize());
+      updateTerminalLengthAndPageSize(newTerminalSize, 
topScreenView.getPageSize());
       topScreenView.clearTerminal();
     }
 
@@ -98,6 +115,7 @@ public class TopScreenPresenter {
     topScreenView.refreshTerminal();
 
     lastRefreshTimestamp = System.currentTimeMillis();
+    iterations++;
     return refreshDelay.get();
   }
 
@@ -242,7 +260,7 @@ public class TopScreenPresenter {
   }
 
   private void switchMode(Mode nextMode) {
-    topScreenModel.switchMode(nextMode, null, false);
+    topScreenModel.switchMode(nextMode, false, null);
     reset();
   }
 
@@ -258,18 +276,22 @@ public class TopScreenPresenter {
   }
 
   private void reset() {
-    initFieldDisplayMapAndFieldLengthMap();
+    initFieldDisplayMapAndFieldLengthMap(null);
     adjustFieldLength.set(true);
     paging.init();
     horizontalScroll = 0;
     topScreenView.clearTerminal();
   }
 
-  private void initFieldDisplayMapAndFieldLengthMap() {
+  private void initFieldDisplayMapAndFieldLengthMap(@Nullable List<Field> 
initialFields) {
     fieldDisplayMap.clear();
     fieldLengthMap.clear();
     for (FieldInfo fieldInfo : topScreenModel.getFieldInfos()) {
-      fieldDisplayMap.put(fieldInfo.getField(), 
fieldInfo.isDisplayByDefault());
+      if (initialFields != null) {
+        fieldDisplayMap.put(fieldInfo.getField(), 
initialFields.contains(fieldInfo.getField()));
+      } else {
+        fieldDisplayMap.put(fieldInfo.getField(), 
fieldInfo.isDisplayByDefault());
+      }
       fieldLengthMap.put(fieldInfo.getField(), fieldInfo.getDefaultLength());
     }
   }
@@ -288,7 +310,7 @@ public class TopScreenPresenter {
 
         double delay;
         try {
-          delay = Double.valueOf(inputString);
+          delay = Double.parseDouble(inputString);
         } catch (NumberFormatException e) {
           return goToMessageMode(screen, terminal, row, "Unacceptable floating 
point");
         }
@@ -329,4 +351,8 @@ public class TopScreenPresenter {
     filters.addAll(topScreenModel.getPushDownFilters());
     return new FilterDisplayModeScreenView(screen, terminal, row, filters, 
topScreenView);
   }
+
+  public boolean isIterationFinished() {
+    return iterations >= numberOfIterations;
+  }
 }
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java
 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java
index 9a29177..da5c883 100644
--- 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java
+++ 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java
@@ -23,6 +23,8 @@ import java.util.List;
 import java.util.stream.Collectors;
 import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.hbtop.Record;
+import org.apache.hadoop.hbase.hbtop.RecordFilter;
+import org.apache.hadoop.hbase.hbtop.field.Field;
 import org.apache.hadoop.hbase.hbtop.mode.Mode;
 import org.apache.hadoop.hbase.hbtop.screen.AbstractScreenView;
 import org.apache.hadoop.hbase.hbtop.screen.Screen;
@@ -50,13 +52,16 @@ public class TopScreenView extends AbstractScreenView {
   private static final int RECORD_START_ROW = 9;
 
   private final TopScreenPresenter topScreenPresenter;
-  private int pageSize;
+  private Integer pageSize;
 
   public TopScreenView(Screen screen, Terminal terminal, long 
initialRefreshDelay, Admin admin,
-    Mode initialMode) {
+    Mode initialMode, @Nullable List<Field> initialFields, @Nullable Field 
initialSortField,
+    @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> 
initialFilters,
+    long numberOfIterations) {
     super(screen, terminal);
     this.topScreenPresenter = new TopScreenPresenter(this, initialRefreshDelay,
-      new TopScreenModel(admin, initialMode));
+      new TopScreenModel(admin, initialMode, initialFields, initialSortField,
+        initialAscendingSort, initialFilters), initialFields, 
numberOfIterations);
   }
 
   @Override
@@ -66,11 +71,12 @@ public class TopScreenView extends AbstractScreenView {
     setTimer(delay);
   }
 
+  @Nullable
   @Override
   public ScreenView handleTimer() {
     long delay = topScreenPresenter.refresh(false);
     setTimer(delay);
-    return this;
+    return topScreenPresenter.isIterationFinished() ? null : this;
   }
 
   @Nullable
@@ -79,39 +85,39 @@ public class TopScreenView extends AbstractScreenView {
     switch (keyPress.getType()) {
       case Enter:
         topScreenPresenter.refresh(true);
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case ArrowUp:
         topScreenPresenter.arrowUp();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case ArrowDown:
         topScreenPresenter.arrowDown();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case ArrowLeft:
         topScreenPresenter.arrowLeft();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case ArrowRight:
         topScreenPresenter.arrowRight();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case PageUp:
         topScreenPresenter.pageUp();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case PageDown:
         topScreenPresenter.pageDown();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case Home:
         topScreenPresenter.home();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case End:
         topScreenPresenter.end();
-        return this;
+        return topScreenPresenter.isIterationFinished() ? null : this;
 
       case Escape:
         return null;
@@ -182,13 +188,18 @@ public class TopScreenView extends AbstractScreenView {
     return this;
   }
 
+  @Nullable
   @Override
   public TerminalSize getTerminalSize() {
     TerminalSize terminalSize = super.getTerminalSize();
+    if (terminalSize == null) {
+      return null;
+    }
     updatePageSize(terminalSize);
     return terminalSize;
   }
 
+  @Nullable
   @Override
   public TerminalSize doResizeIfNecessary() {
     TerminalSize terminalSize = super.doResizeIfNecessary();
@@ -206,7 +217,8 @@ public class TopScreenView extends AbstractScreenView {
     }
   }
 
-  public int getPageSize() {
+  @Nullable
+  public Integer getPageSize() {
     return pageSize;
   }
 
@@ -244,8 +256,14 @@ public class TopScreenView extends AbstractScreenView {
 
   private void showRecords(List<Header> headers, List<Record> records, Record 
selectedRecord) {
     TerminalPrinter printer = getTerminalPrinter(RECORD_START_ROW);
+    int size;
+    if (pageSize != null) {
+      size = pageSize;
+    } else {
+      size = records.size();
+    }
     List<String> buf = new ArrayList<>(headers.size());
-    for (int i = 0; i < pageSize; i++) {
+    for (int i = 0; i < size; i++) {
       if(i < records.size()) {
         Record record = records.get(i);
         buf.clear();
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java
 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java
index 248bb58..c834b75 100644
--- 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java
+++ 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java
@@ -29,7 +29,7 @@ import org.apache.yetus.audience.InterfaceAudience;
 public interface Terminal extends Closeable {
   void clear();
   void refresh();
-  TerminalSize getSize();
+  @Nullable TerminalSize getSize();
   @Nullable TerminalSize doResizeIfNecessary();
   @Nullable KeyPress pollKeyPress();
   CursorPosition getCursorPosition();
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminal.java
 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminal.java
new file mode 100644
index 0000000..19d6426
--- /dev/null
+++ 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminal.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.hbtop.terminal.impl.batch;
+
+import edu.umd.cs.findbugs.annotations.Nullable;
+import org.apache.hadoop.hbase.hbtop.terminal.CursorPosition;
+import org.apache.hadoop.hbase.hbtop.terminal.KeyPress;
+import org.apache.hadoop.hbase.hbtop.terminal.Terminal;
+import org.apache.hadoop.hbase.hbtop.terminal.TerminalPrinter;
+import org.apache.hadoop.hbase.hbtop.terminal.TerminalSize;
+
+public class BatchTerminal implements Terminal {
+
+  private static final TerminalPrinter TERMINAL_PRINTER = new 
BatchTerminalPrinter();
+
+  @Override
+  public void clear() {
+  }
+
+  @Override
+  public void refresh() {
+    // Add a new line
+    TERMINAL_PRINTER.endOfLine();
+  }
+
+  @Nullable
+  @Override
+  public TerminalSize getSize() {
+    return null;
+  }
+
+  @Nullable
+  @Override
+  public TerminalSize doResizeIfNecessary() {
+    return null;
+  }
+
+  @Nullable
+  @Override
+  public KeyPress pollKeyPress() {
+    return null;
+  }
+
+  @Override
+  public CursorPosition getCursorPosition() {
+    return null;
+  }
+
+  @Override
+  public void setCursorPosition(int column, int row) {
+  }
+
+  @Override
+  public void hideCursor() {
+  }
+
+  @Override
+  public TerminalPrinter getTerminalPrinter(int startRow) {
+    return TERMINAL_PRINTER;
+  }
+
+  @Override
+  public void close() {
+  }
+}
diff --git 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java
 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java
similarity index 54%
copy from 
hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java
copy to 
hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java
index 248bb58..db7a9e7 100644
--- 
a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java
+++ 
b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java
@@ -15,25 +15,40 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.hadoop.hbase.hbtop.terminal;
+package org.apache.hadoop.hbase.hbtop.terminal.impl.batch;
 
-import edu.umd.cs.findbugs.annotations.Nullable;
-import java.io.Closeable;
-import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.hadoop.hbase.hbtop.terminal.TerminalPrinter;
 
+public class BatchTerminalPrinter implements TerminalPrinter {
 
-/**
- * The terminal interface that is an abstraction of terminal screen.
- */
-@InterfaceAudience.Private
-public interface Terminal extends Closeable {
-  void clear();
-  void refresh();
-  TerminalSize getSize();
-  @Nullable TerminalSize doResizeIfNecessary();
-  @Nullable KeyPress pollKeyPress();
-  CursorPosition getCursorPosition();
-  void setCursorPosition(int column, int row);
-  void hideCursor();
-  TerminalPrinter getTerminalPrinter(int startRow);
+  @Override
+  public TerminalPrinter print(String value) {
+    System.out.print(value);
+    return this;
+  }
+
+  @Override
+  public TerminalPrinter startHighlight() {
+    return this;
+  }
+
+  @Override
+  public TerminalPrinter stopHighlight() {
+    return this;
+  }
+
+  @Override
+  public TerminalPrinter startBold() {
+    return this;
+  }
+
+  @Override
+  public TerminalPrinter stopBold() {
+    return this;
+  }
+
+  @Override
+  public void endOfLine() {
+    System.out.println();
+  }
 }
diff --git 
a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java
 
b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java
index 08a399c..85b9010 100644
--- 
a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java
+++ 
b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java
@@ -63,7 +63,7 @@ public class TestTopScreenModel {
   @Before
   public void setup() throws IOException {
     
when(admin.getClusterMetrics()).thenReturn(TestUtils.createDummyClusterMetrics());
-    topScreenModel = new TopScreenModel(admin, Mode.REGION);
+    topScreenModel = new TopScreenModel(admin, Mode.REGION, null, null, null, 
null);
 
     fields = Mode.REGION.getFieldInfos().stream()
       .map(FieldInfo::getField)
@@ -84,17 +84,17 @@ public class TestTopScreenModel {
     TestUtils.assertRecordsInRegionMode(topScreenModel.getRecords());
 
     // Namespace Mode
-    topScreenModel.switchMode(Mode.NAMESPACE, null, false);
+    topScreenModel.switchMode(Mode.NAMESPACE, false, null);
     topScreenModel.refreshMetricsData();
     TestUtils.assertRecordsInNamespaceMode(topScreenModel.getRecords());
 
     // Table Mode
-    topScreenModel.switchMode(Mode.TABLE, null, false);
+    topScreenModel.switchMode(Mode.TABLE, false, null);
     topScreenModel.refreshMetricsData();
     TestUtils.assertRecordsInTableMode(topScreenModel.getRecords());
 
     // Namespace Mode
-    topScreenModel.switchMode(Mode.REGION_SERVER, null, false);
+    topScreenModel.switchMode(Mode.REGION_SERVER, false, null);
     topScreenModel.refreshMetricsData();
     TestUtils.assertRecordsInRegionServerMode(topScreenModel.getRecords());
   }
@@ -168,7 +168,7 @@ public class TestTopScreenModel {
 
   @Test
   public void testSwitchMode() {
-    topScreenModel.switchMode(Mode.TABLE, null, false);
+    topScreenModel.switchMode(Mode.TABLE, false, null);
     assertThat(topScreenModel.getCurrentMode(), is(Mode.TABLE));
 
     // Test for initialFilters
@@ -176,7 +176,7 @@ public class TestTopScreenModel {
       RecordFilter.parse("TABLE==table1", fields, true),
       RecordFilter.parse("TABLE==table2", fields, true));
 
-    topScreenModel.switchMode(Mode.TABLE, initialFilters, false);
+    topScreenModel.switchMode(Mode.TABLE, false, initialFilters);
 
     assertThat(topScreenModel.getFilters().size(), is(initialFilters.size()));
     for (int i = 0; i < topScreenModel.getFilters().size(); i++) {
@@ -186,13 +186,13 @@ public class TestTopScreenModel {
 
     // Test when keepSortFieldAndSortOrderIfPossible is true
     topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields);
-    topScreenModel.switchMode(Mode.NAMESPACE, null, true);
+    topScreenModel.switchMode(Mode.NAMESPACE, true, null);
     assertThat(topScreenModel.getCurrentSortField(), is(Field.NAMESPACE));
   }
 
   @Test
   public void testDrillDown() {
-    topScreenModel.switchMode(Mode.TABLE, null, false);
+    topScreenModel.switchMode(Mode.TABLE, false, null);
     topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields);
     topScreenModel.refreshMetricsData();
 
diff --git 
a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java
 
b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java
index 6bd214a..d218dd5 100644
--- 
a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java
+++ 
b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java
@@ -95,7 +95,8 @@ public class TestTopScreenPresenter {
     when(topScreenModel.getRecords()).thenReturn(TEST_RECORDS);
     when(topScreenModel.getSummary()).thenReturn(TEST_SUMMARY);
 
-    topScreenPresenter = new TopScreenPresenter(topScreenView, 3000, 
topScreenModel);
+    topScreenPresenter = new TopScreenPresenter(topScreenView, 3000, 
topScreenModel,
+      null, Long.MAX_VALUE);
   }
 
   @Test

Reply via email to