cla/reg - Registry Manipulation

The Clarive registry holds extension points to many parts of the system, both client and server.

These functions are mostly useful in init/ plugin entrypoints to register items like palette operations (services), menu entries, events and others.

Create a file in CLARIVE_BASE/plugins/myplugin/init/myplugin-init.js for registration and hooks to be implemented at Clarive system start.

When the Clarive server (web or dispatcher) starts in debug mode (ie. cla web-start -d), it will report all plugin init registrations.

For example:

(D)2018-11-06 17:23:12.183[22795] Running plugin init: .../plugins/myplugin/init/my-controller.js
(D)2018-11-06 17:23:12.197[22795] Registered controller path /plugin/myplugin/envs
(D)2018-11-06 17:23:12.197[22795] Registered controller path /plugin/myplugin/servers

reg.register(key, config)

Creates a registry entry in Clarive.

Registry entries can typically be of the following types:

  • event. - an event that will be later fired by the plugin.
  • dashlet. - a dashlet that can be introduced into a dashboard.
  • service. - an operation that can be used in rules.
  • action. - a security action, available when creating roles.
  • config. - an "Advanced Config" key that can be changed by admins.

  • key: a string that uniquely identifies the registered item. It should follow this pattern: [event|service|dashlet|config|action].[yourpluginid].[eventname]

  • config: a data structure (Javascript object) that describes the

Registering a new plugin event:

var reg = require('cla/reg');
reg.register('event.myplugin.test',{ name: 'Test Event' });

Registering a config key:

var reg = require('cla/reg');
reg.register('config.myplugin',
    {
        name: 'Config my plugin',
        metadata: [
            { id: 'timeout', label: 'Plugin Timeout', default: 90 },
            { id: 'frequency', label: 'Plugin Frequency', default: 120 }
        ]
    }
);

// then later, use it in your code:

var config = require('cla/config');
var pluginConfig = config.get('config.myplugin');
console.log('The timeout is = ' + pluginConfig.timeout );

Registering a security action:

var reg = require('cla/reg');
reg.register('action.myplugin.allowed',
    {
        name: 'Action that allows users to do something with this plugin'
    }
);

// then later...

var user = ci.findOneCi({ collection: 'user', username: 'janet' });

var allowed = user.hasAction('action.myplugin.allowed');
if( allowed ) {
    console.log('user is good for this feature');
}

reg.launch(key, parameters)

Launches a registered service. Services are also known as operations, which are available in the rule designer palette to build rules.

var reg = require('cla/reg');

reg.register('service.test',{
    name: 'Foo Service',
    handler: function(){ return 99 }
});

reg.launch('service.test', { name: 'just trying this out', config: { foo: 'bar' } });

Options:

  • config - a config object to be sent to the handler.
  • name - reports the op name so that its logging information is more descriptive.
  • dataKey - reports the op name so that its logging information is more descriptive.
  • stash - an alternative stash; defaults to the current stash.

reg.fireEvent(eventKey, eventData, eventFunction)

Fires an event.

If you register a new event in your plugin, you probably also want to be able to fire it. This function fires events.

  • eventKey - the key string of the event we are firing, ie. event.myplugin.someevent.
  • eventData - any random data (Javascript object) from our plugin and related to the event that we want to share with rules or other extensions that may customize the event.
  • eventFunction - this is the core code that runs the event logic. This is optional, but it allows rules and other hooks to prevent it from executing. Data returned by the eventFunction will be merged into the eventData and will be accessible to after event hooks and rules (online and offline).

In the following example we register and fire an event:

var reg = require('cla/reg');

reg.register('event.myplugin.something', {
    name: 'Event fired when something happens'
});

// then later in your plugin...

reg.fireEvent(
    'event.myplugin.something',
    { foo: 123, bar: [1,2,3] },
    function(stash){
        console.log('This is the core of what happens in my event');
        console.log('Got foo here=' + stash.foo);

        // return values get pushed into the stash for event hooks to use
        return { result: 'this result goes back into the stash' };
    }
);

Registering and firing events in your plugin is a great way to enable user customization (with rules) and interop with other plugins. We recommend using it for any pluging features that you may deem extensible or customizable by others.

Warning

Do not fire Clarive's internal events from within your plugin! (example: event.topic.create) Unexpected things may happen. Use fireEvent for firing events your created in your plugin.

reg.beforeEvent(eventKey, hookFunction)

Runs the hookFunction code every time an event is fired, before the event logic run.

reg.afterEvent(eventKey, hookFunction)

Runs the hookFunction code every time an event is fired, after the event logic run.

The before event hook enables your plugin to be called immediately before the event's core logic runs.

The after event This means your plugin can alter Clarive's core behavior functionality. Use it wisely.

  • eventKey: the event key string that identifies the event to hook to.
  • hookFunction: your registered hook function that will be called every time the event fires. The function will receive the event data as the first argument.

Before Events

If an error is thrown from a before event hook, the event logic will not execute. This is useful for adding ad-hoc verifications to system logic.

Also, before events can change the data being sent to the event core logic, which is useful for modifying content like topic fields, adding descriptions, etc.

Warning

Very few event hooks need to run before events, so think again before choosing your hook to be beforeEvent.

After Events

After-hook code executes immediately after the event has fired and it's core logic has finished, but before control is returned to the user (in case of online events).

After-hook events are useful when additional modifications need to be performed once data has been created.

Some examples:

var reg = require('cla/reg');

reg.afterEvent("event.clarive.started", function() {
    console.log("CLARIVE has started successfully");
});

reg.beforeEvent("event.auth.ok", function(stash) {
    console.log("New user login: " + stash.username);

    if( stash.username === "bob" ) {
        throw new Error('Bob is not authorized to login');
    }
});

reg.afterEvent("event.topic.create", function(stash) {
    console.log("Topic created with title = " + stash.title);
});

For a complete list of events, check the event ids available in the rule designer web interface under Admin:Rule Designer.

Note

Do not execute long running code in the beforeEvent() or afterEvent() methods. It will negativelly affect the user experience directly as online event hooks are sequential and hold up the UI while executing.

reg.controller(url, { authenticate: boolean, handler: function })

Registers a controller endpoint.

Controllers are web endpoints that can be called directly into the Clarive server.

  • url - entry endpoint. This url will be accessible through https://clariveserver:port/plugin/[pluginid]/[url].

  • handler - the handler function is mandatory. This is the code that will be called at the endpoint with every request. The handler will receive a request (as first argument) and generate a response (the second argument). The 3rd argument is the user object that has information of the logged in user session.

  • authenticate - a boolean indicating if the endpoint requires the user to be authenticate, or is available to any user.

For more information, please refer to the controller reference document.

var reg = require('cla/reg');

reg.controller('foobar',{
    authenticate: false,
    handler: function(req,res){
        res.body( "hello world" );
    }
});

Running Services - Examples

Using reg.launch() any rule palette operation may be called from a plugin, making it easy to leverage the power of complex functionality already available in the core of Clarive or as external plugins in your own plugin.

In order to execute services within plugins, you need to know which variables have to be passed to them in order for them to function correctly. Please check the rule designer interface for hints on what service needs which variables by selecting the Metadata tab for each operation.

Among the items that may be called are: launching remote scripts, shipping files via SSH, creation of Topics, etc.

Below are a number of examples of palette items that may be called, along with the variables needed for these. Not all variables are needed in every case, but we have listed here all those that may be used.

Executing remote commands (service.scripting.remote):

This is the service responsible for executing commands remotely.

reg.launch('service.scripting.remote', {
    name: 'Remote launch', // Name of the task to be executed
    config: {
        errors: 'fail', // Type of errors to be monitored
        server: '1234', // Server ID on which it will be executed
        user: 'clarive', // User for connecting to the server
        path: 'ls -l', // Command we wish to launch
        output_error: '', // Regular expressions for monitoring errors
        output_warn: '', // Regular expressions for monitoring errors
        output_capture: '', // Regular expressions for monitoring errors
        output_ok: '', // Regular expressions for monitoring errors
        meta: {foor: bar}, // Metadata of the service where it is executed
        rc_ok: '200', // rc Ok code for monitoring errors
        rc_error: '404', // rc Error code for monitoring errors
        rc_warn: '302' // rc Warn code for monitoring errors
    }
});

Shipping files remotely (service.fileman.ship)

Service responsible for shipping files remotely to another server.

reg.launch('service.fileman.ship', {
    name: 'Remote ship', // Name of the task to be executed
    config: {
        server: '1234', // Server ID to which the file is to be shipped
        user: 'clarive', // User for connecting to the server
        recursive: "0", // Perform the operation recursively or not
        local_mode: "local_files", // Mode for shipping local files
        local_path: "/Home/", // Path to the file to be shipped
        remote_path: "/tmp/", // Directory of the remote server to which we would like to ship the file
        exist_mode_local: "skip", // Action mode when file not found
        rel_path: "file_only", // Shipping mode only for files or retaining the job path
        exist_mode: "reship", // Action mode when files have already been shipped by the job
        backup_mode: "none", // File backup mode
        rollback_mode: "none", // Rollback mode
        track_mode: "none", // File tracking mode
        audit_tracked: "none", // File audit mode
        chown: "", // chown permissions
        chmod: "", // chmod permissions
        max_transfer_chunk_size: "", // Maximum transfer size
        copy_attrs: "0" // Copy file attributes
    }
});

Change in Topic Status (service.topic.change_status)

Service used for changing the Topic Status in Clarive.

reg.launch('service.topic.change_status', {
    name: 'Change topic status', // Name of the task to be executed
    config: {
        topics: '123', // ID of the Topic we would like to change
        old_status: '3', // ID of the status from which the Topic is to be changed
        new_status: '4', // ID of the new Status we would like to assign to the Topic
        username: 'clarive'// User to which the change in Status is to be assigned
    }
});

Creation of Topics ('service.topic.create')

Service used for creating Topics in Clarive.

reg.launch('service.topic.create', {
    name: 'Create topic', // Name of the task to be executed
    config: {
        title: 'Topic title', // Title of the Topic that will be created
        category: '34', // ID of the category to which the Topic belongs
        status: '3', // ID of the Initial Status with which it is created
        username: 'clarive', // User to which creation of the Topic is assigned
        variables: {desc: 'hello'} // The different variables or fields inherent to the Topic to be created
    }
});

Topic Update ('service.topic.update')

Service used for updating Topic content in Clarive.

reg.launch('service.topic.update', {
        name: 'Update topic', // Name of the task to be executed
        config: {
        mid: '123', // ID of the Topic we would like to change
        username: 'clarive', // User to which Topic creation is assigned
        variables: {desc: 'hello'} // The different variables or fields inherent to the Topic to be updated
    }
});

Deleting Topics ('service.topic.delete')

Service used for deleting Topics in Clarive.

reg.launch('service.topic.delete', {
    name: 'Delete topic', // Name of the task to be executed
    config: {
        topics: '123', // ID of the Topic we wish to change
        username: 'clarive' // User to which Topic creation is assigned
    }
});