Integrating a Terminal Into Your Application

Lee Painter

Introduction

One major difference between version 3 and earlier version of Terminal Components, was the usage of the 'Session Manager' classes such as SwingTerminalSessionManager. These classes provided a framework for multiple terminals and presented them as tabs (or other container types). This framework has been completely removed in this version and it is up to you to provide such functionality yourself if you need it.

Integrating with an application

Terminal Components comes with a number of different renderers for you to use. Select the article below to see how to set up the renderer for your application environment. Then follow the remaining instructions in this article to obtain a reference to the terminal buffer and to set up a connection to a remote host.

AWT

Swing

SWT

JavaFX

Configure the Terminal

We can set some properties on the display object to customize the terminal, for example, let's make the terminal more retro and create a black background with a green foreground.

display.setBackground(Color.BLACK);
display.setForeground(Color.GREEN);

We can also customize the cursor, here we will make it a blinking block cursor in Yellow.

display.setCursorColors(VDUColor.BLACK, VDUColor.YELLOW);
display.setCursorStyle(VDUDisplay.CURSOR_BLOCK);
display.setCursorBlink(true);

Connecting the Terminal to a process

Before you can connect the terminal to a remote host, you will need a reference to the Terminal Buffer.

Terminal buffer = display.getVDUBuffer();

You will then need to connect the terminal to a pair of I/O streams that come from some kind of remote host or another type of output. This can be completed with a couple of lines of code when you have an Input/OutputStream from the host or process. In this example, the session parameter is a reference to an SSH session created using our SSH API but it could be any type of InputStream available to you that has data you want to display on the terminal.

First connect the output of your process, to the Terminal by creating a TerminalOutputStream. This can then be passed into a utility method to copy from one stream to another. This will output all the data received on the session's InputStream and place it on the Terminal display. Place this on a thread, do not execute this on the UI thread.

IOUtil.copy(session.getInputStream(), new TerminalOutputStream(buffer));

If the process you are using requires user interaction i.e. keystrokes then you should ensure you connect up the Terminal's InputStream. This InputStream receives all the user interaction from the terminal display and so this should be sent to the process. Ensure you also do this on a separate thread.

Here we use the IOUtil utility class from our Maverick Legacy API to copy the streams.

Thread t2=  new Thread() {
   public void run() {
      try {
         IOUtil.copy(buffer.getTerminalInputStream(), session.getOutputStream());
      } catch (Exception e) {
      }
   }
};

t2.start(); 

Connecting an SSH Session

Many of our users want to connect the terminal to an SSH session using our Maverick Legacy Client API. Please read the Creating a Connection article for detailed information about setting up an SSH client. We will assume here you have a SshClient instance that is connected and authenticated and ready to start a session.

Before connecting the streams you need to start the shell or execute the command you want to interact with. First, we open a session channel on the SshClient instance.

SshSession session = ssh.openSessionChannel();

We then need to set up the pseudo terminal on the remote host. We will use xterm and we get the number of columns and rows from the Terminal object. The final parameters are width and height which do not apply in this case so we pass a value of zero.

session.requestPseudoTerminal("xterm", 
		buffer.getColumns(), 
		buffer.getRows(), 0, 0);

If you make your UI component resizable then you will want to add a listener to the Terminal to capture changes in terminal dimensions. We need to send these changes back to the SSH server.

buffer.addListener(new TerminalListenerAdapter() {
   public void screenResize(Terminal terminal, int cols, int rows, boolean remote) {
      if(!remote) {
         try {
            session.changeTerminalDimensions(cols, rows, 0, 0);
         } catch (SshException e) {
         }
      }
   }
});

Then we clear the screen for good measure and start the remote shell.

buffer.clearScreen();
session.startShell();

Now as we demonstrated above, we connect the streams.

Thread t2=  new Thread() {
   public void run() {
      try {
         IOUtil.copy(buffer.getTerminalInputStream(), session.getOutputStream());
      } catch (Exception e) {
      }
   }
};
t2.start();
				
IOUtil.copy(session.getInputStream(), new TerminalOutputStream(buffer));

 

The image shows a Swing version of the example code outlined in this article.