Package org.jboss.aesh.terminal

Source Code of org.jboss.aesh.terminal.POSIXTerminal

/*
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jboss.aesh.terminal;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jboss.aesh.console.reader.ConsoleInputSession;
import org.jboss.aesh.console.settings.Settings;
import org.jboss.aesh.util.LoggerUtil;

/**
* Terminal that should work on most POSIX systems
*
* @author Ståle W. Pedersen <stale.pedersen@jboss.org>
*/
public class POSIXTerminal extends AbstractTerminal {

    private TerminalSize size;
    private boolean echoEnabled;
    private String ttyConfig;
    private String ttyProps;
    private long ttyPropsLastFetched;
    private boolean restored = false;

    private InputStream input;
    private PrintStream stdOut;
    private PrintStream stdErr;

    private static long TIMEOUT_PERIOD = 3000;

    private static final Logger logger = LoggerUtil.getLogger(POSIXTerminal.class.getName());

    public POSIXTerminal(final Settings settings) {
        super(settings, logger);
    }

    @Override
    public void init(InputStream inputStream, PrintStream stdOut, PrintStream stdErr) {
        // save the initial tty configuration
        try {
            ttyConfig = stty("-g");

            // sanity check
            if ((ttyConfig.length() == 0)
                    || ((!ttyConfig.contains("=")) && (!ttyConfig.contains(":")))) {
                if(settings.isLogging())
                    logger.log(Level.SEVERE, "Unrecognized stty code: "+ttyConfig);
                throw new RuntimeException("Unrecognized stty code: " + ttyConfig);
            }

            // set the console to be character-buffered instead of line-buffered
            // -ixon will give access to ctrl-s/ctrl-q
            stty("-ixon -icanon min 1");

            // disable character echoing
            stty("-echo");
            echoEnabled = false;

            //setting up input
            input =  new ConsoleInputSession(inputStream).getExternalInputStream();
        }
        catch (IOException ioe) {
            if(settings.isLogging())
                logger.log(Level.SEVERE, "tty failed: ",ioe);
        }
        catch (InterruptedException e) {
            if(settings.isLogging())
                logger.log(Level.SEVERE, "failed while waiting for process to end: ",e);
            e.printStackTrace();
        }

        this.stdOut = stdOut;
        this.stdErr = stdErr;
        size = new TerminalSize(getHeight(), getWidth());
    }

    /**
     * @see org.jboss.aesh.terminal.Terminal
     */
    @Override
    public int[] read(boolean readAhead) throws IOException {
        int input = this.input.read();
        int available = this.input.available();
        if(available > 1 && readAhead) {
            int[] in = new int[available];
            in[0] = input;
            for(int c=1; c < available; c++ )
                in[c] = this.input.read();

            return in;
        }
        else
            return new int[] {input};
    }

    @Override
    public TerminalSize getSize() {
        if(propertiesTimedOut()) {
            size.setHeight(getHeight());
            size.setWidth(getWidth());
        }
        return size;
    }

    private int getHeight() {
        int height = 0;
        try {
            height = getTerminalProperty("rows");
        }
        catch (Exception e) {
            if(settings.isLogging())
                logger.log(Level.SEVERE,"Failed to fetch terminal height: ",e);
        }
        //cant use height < 1
        if(height < 1)
            height = 24;

        return height;
    }

    private int getWidth() {
        int width = 0;
        try {
            width = getTerminalProperty("columns");
        }
        catch (Exception e) {
            if(settings.isLogging())
                logger.log(Level.SEVERE,"Failed to fetch terminal width: ",e);
        }
        //cant use with < 1
        if(width < 1)
            width = 80;

        return width;
    }

    /**
     * @see org.jboss.aesh.terminal.Terminal
     */
    @Override
    public boolean isEchoEnabled() {
        return echoEnabled;
    }

    /**
     * @see org.jboss.aesh.terminal.Terminal
     */
    @Override
    public void reset() throws IOException {
        if(!restored) {
            if (ttyConfig != null) {
                try {
                    stty(ttyConfig);
                    ttyConfig = null;
                    restored = true;
                }
                catch (InterruptedException e) {
                    if(settings.isLogging())
                        logger.log(Level.SEVERE,"Failed to reset terminal: ",e);
                }
            }
        }
    }

    private boolean propertiesTimedOut() {
        return (System.currentTimeMillis() -ttyPropsLastFetched) > TIMEOUT_PERIOD;
    }

    private int getTerminalProperty(String prop) throws IOException, InterruptedException {
        // tty properties are cached so we don't have to worry too much about getting term width/height
        if (ttyProps == null || propertiesTimedOut()) {
            ttyProps = stty("-a");
            ttyPropsLastFetched = System.currentTimeMillis();
        }
        // need to be able handle both output formats:
        // speed 9600 baud; 24 rows; 140 columns;
        // and:
        // speed 38400 baud; rows = 49; columns = 111;
        for (String str : ttyProps.split(";")) {
            str = str.trim();
            if (str.startsWith(prop)) {
                int index = str.lastIndexOf(" ");

                return Integer.parseInt(str.substring(index).trim());
            }
            else if (str.endsWith(prop)) {
                int index = str.indexOf(" ");

                return Integer.parseInt(str.substring(0, index).trim());
            }
        }

        return -1;
    }

    /**
     * Run stty with arguments on the active terminal
     *
     * @param args arguments
     * @return output
     * @throws IOException stream
     * @throws InterruptedException stream
     */
    protected static String stty(final String args) throws IOException, InterruptedException {
        return exec("stty " + args + " < /dev/tty").trim();
    }

    /**
     * Run a command and return the output
     *
     * @param cmd what to execute
     * @return output
     * @throws java.io.IOException stream
     * @throws InterruptedException stream
     */
    private static String exec(final String cmd) throws IOException, InterruptedException {
        return exec(new String[] { "sh", "-c", cmd });
    }

    /**
     * Run a command and return the output
     *
     * @param cmd the command
     * @return output
     * @throws IOException stream
     * @throws InterruptedException stream
     */
    private static String exec(final String[] cmd) throws IOException, InterruptedException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();

        Process p = Runtime.getRuntime().exec(cmd);
        int c;
        InputStream in = null;
        InputStream err = null;
        OutputStream out = null;

        try {
            in = p.getInputStream();

            while ((c = in.read()) != -1) {
                bout.write(c);
            }

            err = p.getErrorStream();

            while ((c = err.read()) != -1) {
                bout.write(c);
            }

            out = p.getOutputStream();

            p.waitFor();
        }
        finally {
            try {
                if(in != null)
                    in.close();
                if(err != null)
                    err.close();
                if(out != null)
                    out.close();
            }
            catch (Exception e) {
                logger.log(Level.SEVERE,"Failed to close streams: ",e);
            }
        }

        return new String(bout.toByteArray());
    }

    @Override
    public PrintStream err() {
        return stdErr;
    }

    @Override
    public PrintStream out() {
        return stdOut;
    }

}
TOP

Related Classes of org.jboss.aesh.terminal.POSIXTerminal

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.