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 */
018package org.apache.hadoop.hbase.hbtop.screen;
019
020import edu.umd.cs.findbugs.annotations.Nullable;
021import java.io.Closeable;
022import java.io.IOException;
023import java.util.List;
024import java.util.concurrent.TimeUnit;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.client.Admin;
027import org.apache.hadoop.hbase.client.Connection;
028import org.apache.hadoop.hbase.client.ConnectionFactory;
029import org.apache.hadoop.hbase.hbtop.RecordFilter;
030import org.apache.hadoop.hbase.hbtop.field.Field;
031import org.apache.hadoop.hbase.hbtop.mode.Mode;
032import org.apache.hadoop.hbase.hbtop.screen.top.TopScreenView;
033import org.apache.hadoop.hbase.hbtop.terminal.KeyPress;
034import org.apache.hadoop.hbase.hbtop.terminal.Terminal;
035import org.apache.hadoop.hbase.hbtop.terminal.impl.TerminalImpl;
036import org.apache.hadoop.hbase.hbtop.terminal.impl.batch.BatchTerminal;
037import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
038import org.apache.yetus.audience.InterfaceAudience;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042/**
043 * This dispatches key presses and timers to the current {@link ScreenView}.
044 */
045@InterfaceAudience.Private
046public class Screen implements Closeable {
047  private static final Logger LOGGER = LoggerFactory.getLogger(Screen.class);
048  private static final long SLEEP_TIMEOUT_MILLISECONDS = 100;
049
050  private final Connection connection;
051  private final Admin admin;
052  private final Terminal terminal;
053
054  private ScreenView currentScreenView;
055  private Long timerTimestamp;
056
057  public Screen(Configuration conf, long initialRefreshDelay, Mode initialMode,
058    @Nullable List<Field> initialFields, @Nullable Field initialSortField,
059    @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> initialFilters,
060    long numberOfIterations, boolean batchMode) throws IOException {
061    connection = ConnectionFactory.createConnection(conf);
062    admin = connection.getAdmin();
063
064    // The first screen is the top screen
065    if (batchMode) {
066      terminal = new BatchTerminal();
067    } else {
068      terminal = new TerminalImpl("hbtop");
069    }
070    currentScreenView = new TopScreenView(this, terminal, initialRefreshDelay, admin, initialMode,
071      initialFields, initialSortField, initialAscendingSort, initialFilters, numberOfIterations);
072  }
073
074  @Override
075  public void close() throws IOException {
076    try {
077      admin.close();
078    } finally {
079      try {
080        connection.close();
081      } finally {
082        terminal.close();
083      }
084    }
085  }
086
087  public void run() {
088    currentScreenView.init();
089    while (true) {
090      try {
091        KeyPress keyPress = terminal.pollKeyPress();
092
093        ScreenView nextScreenView;
094        if (keyPress != null) {
095          // Dispatch the key press to the current screen
096          nextScreenView = currentScreenView.handleKeyPress(keyPress);
097        } else {
098          if (timerTimestamp != null) {
099            long now = EnvironmentEdgeManager.currentTime();
100            if (timerTimestamp <= now) {
101              // Dispatch the timer to the current screen
102              timerTimestamp = null;
103              nextScreenView = currentScreenView.handleTimer();
104            } else {
105              TimeUnit.MILLISECONDS
106                .sleep(Math.min(timerTimestamp - now, SLEEP_TIMEOUT_MILLISECONDS));
107              continue;
108            }
109          } else {
110            TimeUnit.MILLISECONDS.sleep(SLEEP_TIMEOUT_MILLISECONDS);
111            continue;
112          }
113        }
114
115        // If the next screen is null, then exit
116        if (nextScreenView == null) {
117          return;
118        }
119
120        // If the next screen is not the previous, then go to the next screen
121        if (nextScreenView != currentScreenView) {
122          currentScreenView = nextScreenView;
123          currentScreenView.init();
124        }
125      } catch (Exception e) {
126        LOGGER.error("Caught an exception", e);
127      }
128    }
129  }
130
131  public void setTimer(long delay) {
132    timerTimestamp = EnvironmentEdgeManager.currentTime() + delay;
133  }
134
135  public void cancelTimer() {
136    timerTimestamp = null;
137  }
138}