Plugins Architecture

Overview

For those familiar with the Eclipse architecture, AjaXplorer is based on the same approach : all features provided by the application are packed as « plugins ». Even the GUI itself is a plugin. This allow a huge modularity in creating features, overriding them, creating dependencies between them, etc. Some plugin will implement a given interface or abstract PHP class to give a precise set of features that are « understood » by the core of the application (like the Authentification plugins for example), other can add purely custom features to access a given set of data, manipulate it, add a specific « hello world » button somewhere in the application, etc…

A plug-in is « auto-declarative » via a specific XML file, called manifest.xml. This file contains all information needed to understand how it should be initialized and used, it’s declaring all necessary files and resources used by this plugin, and it will be able to have an impact on server and/or the client side. If the manifest.xml is present inside the plugin folder and its syntax is ok, the plugin can be activated. This is done inside the conf.php file, where the application will declare which plugins are used to create itself. As a namespace prefix is used for all plugins (auth.serial, editor.audio, etc), if the whole namespace is already declared in the conf.php via the « * » wildcard, your plugin will be ready to use.

1$ACTIVE_PLUGINS = array(« editor.* », « gui.ajax », « hook.* »);

Actions

Globally, the key concept that is shared by both the server and the client, and that the plugins will create, extend or override, are the « actions« . Declaring an action « my_action » inside a plugin will allow you to both (or one of both) :

Trigger a JavaScript code snippet on the client side when calling ajaxplorer.fireAction(« my_action »). Don’t worry, generally this action will be also declared to appear as a button in the toolbar, or right-click menu, so you won’t have to bother for this fireAction() call, this is just what the button click does (but it can be interesting to know you can trigger your action manually via a firebug console call for example).
Call a user-defined PHP function (« callback ») to answer a query when calling « my_action » : remember the paramenter get_action described above in this tutorial? This is when it appears : your plugin will define a given function that will be called by the application when content.php?get_action=my_action is called by the client. All http parameters are passed to your callback, so you can do exactly anything you want with it.
As you should understand, with this simple system, a plugin can indeed declare a « whatever-you-want-that-has-nothing-to-do-with-file-manipulation-or-data-browsing » action! You can trigger, from withing a very simple plugin declaration (XML file), a javascript call to your custom action on the PHP server.

Plugins can do much more, particularly by customizing GUI components on the fly on the client side. But to understand this we first have to introduce the XML Registry notion.

Building XML Registry from plugins manifests

Seeing plugins as registry contributions

Given this plugin architecture, the registry is here to gather all informations about the currently available (and active) plugins and feed the server and the client with the data they need.As nearly everything in plugins is defined inside XML, it is thus logic that this registry is itself a « big » XML Document, that merges all informations from all plugins. And in fact, you should see it the other way round : every XML node declared somewhere in the XML manifest file of the plugins are just fragments of a bigger document, the XML registry. This allows to merge XML branches that have the same parent node into one.

XML Merging example

For example, if one active plugin contains the node plugin/actions/action[name='action1'] and another one contains the same kind of structure with [name='action2'], both <action> nodes will be merged under one unique <actions> branch in the registry. Going further, if a third plugin contains a node plugin/actions/action[name='action1']/action_detail, this <action_detail> subnode will be appended to the <action name=’actions1′> node declared by the first plugin inside the registry. Want to understand this better? Open some manifest.xml files that are inside plugins you are indeed using, then call content.php?get_action=get_xml_registry to see the big picture!

This mechanism of XML merging is one of the important legs of the plugins architecture, as it allows to dynamically append or overwrite the XML contributions of a given plugin from within another one! And since this XML registry is the unique interface between the world and the plugin, and that all Javascript or PHP calls are declared in this XML, you can understand the power of this extension mechanism. In fact, it’s clearly converging with the well-known Eclipse Osgi architecture.

Importing external XML Nodes

Last thing need to use these XML files nearly as a language scripting is to be able to insert a given set of XML from another file into a Manifest. For example, the FTP plugin is using all the same actions as the FS plugin, so it would be useless to have to re-declare all actions definitions in the FTP plugin. The <external_file> key is here to do the job : with an include/exclude mechanism that takes XPath expression as arguments, it allows you to import all the nodes returned by the include expression inside your current XML.

Dependencies mechanism

At this point, you might ask your self « how to be sure that one plugin will be loaded after another? » so that plugin B overrides plugin A data and not the opposite? The third leg of the plugin mechanism indeed resides in the « dependencies » mechanism, once again declared in the manifest.xml file. If a plugin B declares that it depends on plugin A, it will indeed be loaded (and integrated to the registry) after plugin A, or not loaded at all if plugin A is not present. This mechanism can play at load level and at activation level.

How the registry is changing in time

Now that you understand that the registry is built from the bunch of plugins contributions, you must understand how central it is in the way application, particularly the GUI. By nature, some plugins (namely the access.*, auth.* and serial.* ones) can have only one instance linked to a given state of the application. For example, even if auth.serial, auth.remote, auth.ldap, etc, are available plugins, only one can be active at a time in each category of plugin. Going further, the active plugin in this given category can dynamically change its own registry contributions, depending on the state of the current session!

Try this : log in to ajaxplorer, then in another tab call content.php?get_action=get_xml_registry. Observe how the current <user> data is passed inside the registry? Now log out and update your registry : <user> is out. It’s exactly the same when you are switching repository : the registry is totally rebuilt, given the registry_contributions of the active access.* plugin, which is determined by the current repository.

The GUI Ajax client itself is based on the XML Registry : since the XML registry is evolving in time during a session, it must be partially or totally reloaded by the client when some predefined events occur (login, logout, switch_repository, etc…). This allow also to pass GUI components configuration to the client via the registry, and they will be reparsed and reapplyed on-the-fly (if the target components allows it). See Ajax GUI > Updating components configurations.

Next : Gui Architecture

Updated over 8 years ago by Charles du Jeu Admin