Plug-ins and Interfaces

I figured I would talk a bit about the plugin architecture. Delphi has been using a plugin architecture for its IDE since Delphi 1 first came out. Delphi has a very strong component framework called the VCL. Any class derived from TComponent can be registered and have it show up on the IDE toolbar to be used within programs. They provided a package type of project that is used to compile the components into package libraries. Essentially a package is a DLL with functions that allow the package to register the contents with the program loading the library.

One of the 3rd party component libraries that I take advantage of is the TMS Software Plugin Framework. The Plugin Framwork provides a couple of key components. One is the Plugin Manager that you include in the main program, and then another is a component for use in the plugin library. The plugin manager takes care of loading plugins either individually or as a group. It provides event hooks to allow the program to be notified when each plugin is loaded which includes reference to the plugin object.

The plugin side includes a component that manages the registration within the manager (in essentially the same way that Delphi uses for its IDE). The plugin also provides for the ability to register commands that can be bound to visual controls such as menu items or buttons.

A plugin package can also include other components such as forms. One of the more useful Delphi components is a Frame. At design time it looks like a form (window) that you can drop whatever visual controls you want to use. However it actually acts like a panel that can be embeded in other parts of another form. In the SRConsole program when each Frame plugin is loaded the Frame is inserted into a newly created tab in a tab control.

So how does the program know that this plugin has a Frame? And how does it get the Frame object, when the main plugin object doesn’t use Frames? This is where interfaces come in. I defined a TFrameInterface that specifies a function GetFrame. In the Plugin containing the frame, I define that the plugin implements the TFrameInterface by defining the GetFrame function. In the main program, there is a function called Supports which allows me to test if the plugin supports the interface. If it does then it calls GetFrame which returns a reference to the Frame that is defined in the plugin and it inserts into the tab.

One of the other design elements of the system is that I want the programs to be able to support HTTP communication. The Indy HTTP server component is very flexible, but basically acts like a single servlet. To allow for more flexibility I used the plugin system and defined an HTTP Interface that allows some plugins to act as HTTP actions. With a little bit of lookup code, each plugin gets mapped to a base path on the URL and requests get delivered to the appropriate Plugin. The interesting thing with the interfaces is that a plugin can implement more that one interface at time, so if I wanted I could have a single plugin take care of both the Frame interface and the HTTP interface. (For clean separation of concerns, I don’t do this, but the concept is handy).

In the SRConsole application there is an HTTP plugin to handle a login request. It also uses a Frame plugins for each of the different stations. The login registers the name of the user and it performs a lookup (using another HTTP request) to get role information for that user. That determines which of the Frame plugins to display. So if I am only authorized for being a Navigator, I will not see the Weapons screens.

To make things more fun, there is a program called WatchUSB that monitors specified drive letters, looking for a particular config file. When a USB thumb drive is inserted with the file, the program takes the username from the file and calls the login HTTP service. This causes the SRConsole to enable the appropriate screens for that user. When the drive is removed the WatchUSB program sends a logout HTTP call, which causes the SRConsole to hide all of the tabs and set it to wait for the next user to login to the machine.

Next time I will discuss the SRModel application. This also uses interfaces but in a different way.