Loading TOC...
Application Developer's Guide (PDF)

Application Developer's Guide — Chapter 11

System Plugin Framework

This chapter describes the system plugin framework in MarkLogic Server, and includes the following sections:

How MarkLogic Server Plugins Work

Plugins allow you to provide functionality to all of the applications in your MarkLogic Server cluster without the application having to call any code. This section describes the system plugin framework in MarkLogic Server and includes the following parts:

Overview of System Plugins

Plugins are used to automatically perform some functionality before any request is evaluated. A plugin is an XQuery main module, and it can therefore perform arbitrary work. The plugin framework evaluates the main modules in the <marklogic-dir>/Plugins directory before each request is evaluated.

Consider the following notes about how the plugin framework works:

  • After MarkLogic starts up, each module in the Plugins directory is evaluated before the first request against each App Server is evaluated on each node in the cluster. This process repeats again after the Plugins directory is modified.
  • When using a cluster, any files added to the Plugins directory must be added to the Plugins directory on each node in a MarkLogic Server cluster.
  • Any errors (for example, syntax errors) in a plugin module are thrown whenever any request is made to any App Server in the cluster (including the Admin Interface). It is therefore extremely important that you test the plugin modules before deploying them to the <marklogic-dir>/Plugins directory. If there are any errors in a plugin module, you must fix them before you will be able to successfully evaluate any requests against any App Server.
  • Plugins are cached and, for performance reasons, MarkLogic Server only checks for updates once per second, and only refreshes the cache after the Plugins directory is modified; it does not check for modifications of the individual files in the Plugins directory. If you are using an editor to modify a plugin that creates a new file (which in turn modifies the directory) upon each update, then MarkLogic Server will see the update within the next second. If your editor modifies the file in place, then you will have to touch the directory to change the modification date for the latest changes to be loaded (alternatively, you can restart MarkLogic Server). If you delete a plugin from the Plugins directory, it remains registered on any App Servers that have already evaluated the plugin until either you restart MarkLogic Server or another plugin registers with the same name on each App Server.

System Plugins versus Application Plugins

There are two types of plugins in MarkLogic Server: system plugins and application plugins.

System plugins use the built-in plugin framework in MarkLogic Server along with the xdmp:set-server-field and xdmp:get-server-field functions. As described in Overview of System Plugins, system plugins are stored in the <marklogic-dir>/Plugins directory and any errors in them are thrown on all App Servers in the cluster.

Application plugins are built on top of system plugins and are designed for use by applications. Application plugins are stored in the <marklogic-dir>/Assets/plugins/marklogic/appservices directory, and, unlike system plugins, they do not cause errors to other applications if the plugin code contains errors.

The plugin API

The plugin:register function is the mechanism that a plugin module uses to make plugin functionality available anywhere in a MarkLogic Server cluster. The other functions in the plugin API are used to implement the register capability. The plugin API uses server fields (the xdmp:set-server-field and xdmp:get-server-field family of functions) to register the ID and capabilities of each plugin. This API, in combination with the plugin framework that scans the Plugins directory, allows you to create functionality that is available to all App Servers in a MarkLogic Server cluster.

With the plugin API, you can register a set of plugins, and then you can ask for all of the plugins with a particular capability, and the functionality delivered by each plugin is available to your application. For details about the plugin API, see the MarkLogic XQuery and XSLT Function Reference.

Writing System Plugin Modules

A plugin module is just an XQuery main module, so in that sense, you can put any main module in the Plugins directory and you have a plugin. So it really depends what you are trying to accomplish.

Any errors in a system plugin module will cause all requests to hit the error. It is therefore extremely important to test your plugins before deploying them in a production environment.

To use a system plugin, you must deploy the plugin main module to the Plugins directory. To deploy a plugin to a MarkLogic Server cluster, you must copy the plugin main module to the plugin directory of each host in the cluster.

Any system plugin module you write must have a unique filename. Do not modify any of the plugin files that MarkLogic ships in the <marklogic-dir>/Plugins directory. Any changes you make to MarkLogic-installed files in the Plugins directory will be overridden after each upgrade of MarkLogic Server.

Password Plugin Sample

This section describes the password plugin and provides a sample of how to modify it, and contains the following parts:

Understanding the Password Plugin

One use case for a system plugin is to check passwords for things like number of characters, special characters, and so on. Included in the <marklogic-dir>/Samples/Plugins directory are sample plugin modules for password checking.

When a password is set using the security XQuery library (security.xqy), it calls the plugin to check the password using the plugin capability with the following URI:

http://marklogic.com/xdmp/security/password-check

When no plugins are registered with the above capability in the <marklogic-dir>/Plugins directory, then no other work is done upon setting a password. If you include plugins that register with the above password-check capability in the <marklogic-dir>/Plugins directory, then the module(s) are run when you set a password. If multiple plugins are registered with that capability, then they will all run. The order in which they run is undetermined, so the code must be designed such that the order does not matter.

There is a sample included that checks for a minimum length and a sample included that checks to see if the password contains digits. You can create your own plugin module to perform any sort of password checking you require (for example, check for a particular length, the existence of various special characters, repeated characters, upper or lower case, and so on).

Additionally, you can write a plugin to save extra history in the Security database user document, which stores information that you can use or update in your password checking code. The element you can use to store information for password checking applications is sec:password-extra. You can use the sec:user-set-password-extra and sec:user-set-password-extra functions (in security.xqy) to modify the sec:password-extra element in the user document. Use these APIs to create elements as children of the sec:password-extra element.

If you look at the <marklogic-dir>/Samples/Plugins/password-check-minimum-length.xqy file, you will notice that it is a main module with a function that returns empty on success, and an error message if the password is less than a minimum number of characters. In the body of the main module, the plugin is registered with a map that includes its capability (it could register several capabilities, but this only registers one) and a unique name (in this case, the name of the xqy file:

let $map := map:map(),
      $_ := map:put($map, "http://marklogic.com/xdmp/security/password-check",
                    xdmp:function(xs:QName("pwd:minimum-length")))
return
  plugin:register($map, "password-check-minimum-length.xqy")

This registers the function pwd:minimum-length with the http://marklogic.com/xdmp/security/password-check capability, and this particular plugin is called each time a password is set.

Use a unique name to register your plugin (the second argument to plugin:register). If the name is used by another plugin, only one of them will end up being registered (because the other one will overwrite the registration).

If you want to implement your own logic that is performed when a password is checked (both on creating a user and on changing the password), then you can write a plugin, as described in the next section.

Modifying the Password Plugin

The following example shows how to use the sample plugins to check for a minimum password length and to ensure that it contains at least one numeric character.

Any errors in a plugin module will cause all requests to hit the error. It is therefore extremely important to test your plugins before deploying them in a production environment.

To use and modify the sample password plugins, perform the following steps:

  1. Copy the <marklogic-dir>Samples/Plugins/password-check-*.xqy files to the Plugins directory. For example:
    cd /opt/MarkLogic/Plugins
    cp ../Samples/Plugins/password-check-*.xqy .

    If desired, rename the files when you copy them.

  2. If you want to modify any of the files (for example, password-check-minimum-length), open them in a text editor.
  3. Make any changes you desire. For example, to change the minimum length, find the pwd:minimum-length function and change the 4 to a 6 (or to whatever you prefer). When you are done, the body of the function looks as follows:
    if (fn:string-length($password) < 6) 
    then "password too short"
    else ()

    This checks that the password contains at least 6 characters.

  4. Optionally, if you have renamed the files, change the second parameter to plugin:register to the name you called the plugin files in the first step. For example, if you named the plugin file my-password-plugin.xqy, change the plugin:register call as follows:
    plugin:register($map, "my-password-plugin.xqy")
  5. Save your changes to the file.

    If you made a typo or some other mistake that causes a syntax error in the plugin, any request you make to any App Server will throw an exception. If that happens, edit the file to correct any errors.

  6. If you are using a cluster, copy your plugin to the Plugins directory on each host in your cluster.
  7. Test your code to make sure it works the way you intend.

The next time you try and change a password, your new checks will be run. For example, if you try to make a single-character password, it will be rejected.

« Previous chapter
Next chapter »