In this set of articles I explain how we designed and integrated our plugin framework in a web application project. This first article is a resume of existing plugin architectures and our plugin design. In the next articles I will document the implementation of the described plugin architecture and the development of some plugins to equip our web application with new functionalities.
What do we want
- Each of the application users will use different sets of plugins.
- Plugins will be installed, updated and uninstalled without having to restart the server.
- We need communication between the client side of a plugin and its server side. And communication between plugins in the same side.
- Allow users to modify or override existing plugin functions.
- Plugins will be executed asynchronously.
- No need of inheritance hierarchy: plugins can be completely independent, no obligation to use core application's functions.
- Plugins will be shared, and a user may not know the plugin code or if the provider is secure, so we will need to have some kind of security protocols.
Examples of plugin architectures
- Website: https://www.gnu.org/software/emacs/
- Core written in C.
- Emacs is an interpreter for Lisp. So it is very easy to extend emacs. Extensions are written in Emacs Lisp and extend the existing code.
- A command in emacs is a Lisp function and can be invoked with M-x command-name. There are different commands, for managing windows, text management etc. that can also be used in our Lisp extensions.
- There are events for "catching" the keyboard and mouse activity.
- Hooks: We can see hooks as events. "A hook is an ordinary Lisp variable whose value is a list of functions that get executed under specific conditions." Example: make buffer read-only when visiting symbolic link file. The action of visiting a file should trigger a function I wrote. This is where hooks come in. find-file-hooks is the hook every time a new file is visited (There are many hooks). Read more about Elisp hooks.
- Modes: Define basic behavior of the application. For example "Text mode is a major mode for editing human languages", HTML mode is mode for editing HTML documents. A mode can be derived from another mode.
- Macros: Macros enables you to define new control constructs and other language features. A macro is defined much like a function, but instead of telling how to compute a value, it tells how to compute another Lisp expression which will in return compute the value. We call this expression the expansion of the macro. Read more about Elisp macros.
- Website: http://www.eclipse.org/
- Based on Equinox (OSGi framework).
- Plugins are updated without restart. And eclipse mantains the plugins automatically.
- Plugins are in form of package, containing plugin descriptors, plugin resources, implementation code...
- A plugin has different XML files for describing itself and its requirements. Example: "The plug-in manifest file, plugin.xml, describes how the plug-in extends the platform, what extensions it publishes itself, and how it implements its functionality. The manifest file is written in XML and is parsed by the platform when the plug-in is loaded into the platform. All the information needed to display the plug-in in the UI, such as icons, menu items, and so on, is contained in the manifest file. The implementation code, found in a separate Java JAR file, is loaded when, and only when, the plug-in has to be run. This concept is referred to as lazy loading." Read more here.
- Plugins implementation code is written in Java.
- A plugin can depend on other plugins.
- A plugin can extend other plugin functionalities.
- A plugin declare it is extesive "through" an extension point: "When a plug-in wants to allow other plug-ins to extend or customize portions of its functionality, it will declare an extension point. The extension point declares a contract, typically a combination of XML markup and Java interfaces, that extensions must conform to. Plug-ins that want to connect to that extension point must implement that contract in their extension. The key attribute is that the plug-in being extended knows nothing about the plug-in that is connecting to it beyond the scope of that extension point contract. This allows plug-ins built by different individuals or companies to interact seamlessly, even without their knowing much about one another." Read more about what are extensions and extension points.
- You can inject Services to the plugin. Services are software components based on an interface class which provide functionality. Example: ECommandService gives access to existing host application commands and allows you to create and change commands.
- A plugin can use listeners for knowing the state of other plugins. Example: "The host plug-in defines a menu item, which, when selected, causes the state of the subject to be updated. In turn, the state change in the subject causes listener notifications to be broadcast to each listener configured into the system." Read more about listeners
- Extends functionality of the chrome browser.
- A button (Browser action or Page action) in the top of the browser gives access plugin.
- Has a manifest for describing itself. Read Manifest file format.
- Internationalization of variables (chrome.i18n), so they are translated in different languages.
- Communication through some kind of events and listeners. There is intra-extension and inter-extension communication. Read more about message passing in chrome extensions.
- Can do cross server requests.
- Oauth authentication supported in extensions. Extensions vs Plugins:
- Plugins display not nativelly supported content. A plugin example is a plugin for watching videos or flash contents.
- Web Extensions: similar to chrome (they are working on it) Plugins:
- Same as chrome, used for displaying non native supported content.
- Writing GNU Emacs Extensions Editor Customizations and Creations with Lisp (Bob Glickstein) 1997
- Emacs Lisp
- Notes on the Eclipse Plug-in Architecture
- Eclipse, RCP, Plugin and OSGi Development
- Chrome Extensions documentation
- Apple developer: Plug-in Architectures
- Building Your Own Plugin Framework By Gigi Sayfan, November 25, 2007
Our plugin design
Properties of our plugin framework
Here is a table grouping the properties of our plugin framework.
|Plugin file structure||- Manifest (Plugin declaration): Plugin description and requirements.
- Configuration file.
- Resources: Images, JSON files, CSS, HTML...
- Script or executable.
- Temporary files.
|Life of a plugin||- Install.
- Update / mantain plugin.
All of them without having to restart the application.
|Lifecycle during application runtime||- Load plugin (lazy loading | eager loading.), even some kind of "require" to load plugin before having to use it, to speed the application.
- Run plugin functions asynchronously.
- Remove plugin.
Plugin lifecycle will be managed by a Plugin Handler.
- By plugin Id.
- pluginA can fire an event that will execute a certain function in pluginB, this function will recieve pluginA data and do something (this data is somehow standardized).
By default when triggering a plugin, run(data) function is executed if no plugin function specified. If no event specified plugin will be triggered when loaded, anyway when plugins will be loaded we will fire "load-plugins-after" event.
|Communication||- Communication client-server (HTTP).
- Communication with other plugins: parameters, pipes, network based communication, events.
Communication using JSON with some kind of standard structure.
|Acces other plugin state||- Access pluginB from pluginA with pluginB Id.|
|Data||A plugin manipulates data, returns data.|
|Override||Override other plugins functions.|
|Security||- scripts are more secure, code can easily be reviewed.
- Is it secure to have compiled plugins? => Use a script interpreter?
|Documentation||- Technical documentation.
- User documentation.
Our plugins are not defined exclusively as client or server side, they can be both.
They will be installed, updated and uninstalled without the need of restarting the application
Each plugin will be a package containing description files (manifest), configuration files, executables or scripts, resources, temporary files and documentation.
There will be a Plugin Handler in both client and server side to manage the lifecycle of plugins during the application runtime.
The Plugin Handler manage the plugin events. The Plugin Handler will call the plugins functions that have to be called when a certain event is fired.
There will be a client-server plugin communication, so we will need a controller that will handle the client requests and establish communication with the plugins in the server side. This Plugin Controller will also deliver the client plugins when asked.
There will also be a communication between plugins in the same side.
Plugin framework components and flows
Here is a diagram showing the plugin framework components and its flows.
All my issues have to do with the server side. As I said it is written in C++. We develop using C++ REST SDK and...
- Each user of our application will use different plugins and plugin configuration, and C++ REST SDK has no session management.
- There are no examples of authentication server in C++ REST SDK.
- It is difficult to develop compiled plugins in the server side, if we use compiled code there can be security issues.
In the "plug-in architechture II" article I talk about the client side plugin framework documentation, examples and code.