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

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(new TerminalInputStream(buffer), session.getOutputStream());
      } catch (Exception e) { }
   }
}; t2.start();

Connecting the Terminal to a process without using threads (non-blocking I/O)

If your application uses modern non-blocking techniques, such as Java NIO, it may be more convenient to work with the terminal component without using InputStream and OutputStream objects.

The following example uses a mythical 'session' variable that represents some object connected to a remote server, and a callback method this session requires called 'onData' that is invoked when data has been sent from the remote side.

The first part of implementing this technique is similar to the legacy method, you must obtain a reference to the buffer.

Terminal buffer = display.getVDUBuffer();

If you are going to be sending keyboard input back to the remote service, you then install a TerminalInput instance. This may be expressed as a lambda function and receives a byte array of the data to send to the remote service.

buffer.setInput((data, off, len) -> {
    session.write(data, off, len);
});

To pass the data received from your remote host on to the terminal for display will depend on the structure of your program. You will either be receiving some kind of callback from your connection to the remote host, or you will be running your own loop somewhere checking if there is any data available to process.

public void onData(byte[] data) {
    buffer.write(data);
    buffer.flush();
}

You may call write() multiple times before flushing. It depends on the GUI toolkit in use, but a flush() usually signals that the terminal display should be updated. You should avoid unnecessary flushes to avoid affecting performance.

Note, you can actually mix the two techniques. If you have an InputStream available, you can simply copy to the terminal using the stream.

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



Please reference the following articles for more specific information on the different terminal transports supported:

Connecting to a SSH session

Connecting to a Telnet session