Plugin Datasets

The plugin configuration entry allows you to define a dataset which is fetched by executing a Perl module on the server side. The Perl module will have access to the Jarvis database connection, and will have the user authentication tasks already performed. This makes is simple to add new server-side functionality which cannot be easily represented in a SQL statement.

Jarvis plugin datasets should be accessed by the GET or POST methods. None or more plugin elements may be configured.

Configuration

The configuration attributes for a plugin element are as follows.

Attribute Default Notes
dataset (none) Dataset name which is to be interpreted as a plugin rather than a regular dataset. Mandatory parameter.
access (none) This lists the group names that the logged-in user must belong to one of before they can access this plugin. Specify a group name, comma-separated list, * or **. See the documentation for read and write groups on regular datasets.
lib (none) This is an additional directory to be optionally added to the @INC path when loading this module.
If the necessary path for the module is defined using the global <default_lib> element in the configuration, then this attribute is not necessary.
module (none) This is the Perl module name with subdirectories separated by :: and ending in .pm.
add_headers no If yes, Jarvis will add Cookie, Content-Type and Content-Disposition headers to the response. Otherwise the plugin module is entirely responsible for printing ALL headers.

If add_headers is no, be sure to add the header Cache-Control and set the value to no-cache yourself in the outgoing response if you want to avoid responses being cached by IE.
mime_type (none) Only used if add_headers is yes. Allow plugin to override the default MIME type. This takes precedence over any mime type which may be derived from a filename.
filename_parameter (none) Only used if add_headers is yes. We expect a CGI parameter of this name to be present and to contain the returned filename.
default_filename (none) Only used if add_headers is yes. Default filename to use if no filename_parameter is defined or if the CGI parameter named by filename_parameter is not present.
parameter (none) One or more sub-elements defining static parameters to be passed to the plugin. Each parameter element has a name and value attribute.
This allows site-specific plugin configuration to be stored in a common, accessible location. This also allows one Perl module to be used by different plugin instances within the same application, each with their own dataset name and each with slightly different behavior.
debug (none) Enable debug output to standard error for this plugin only. This parameter can not be used to disable global debugging.
dump (none) Enable dump output to standard error for this plugin only. This parameter can not be used to disable global dump output.

Plugin ::do Method

The Plugin is implemented by a ::do method in a Perl Module. The ::do method will receive the following arguments:

The $jconfig context is internal to Jarvis. The following fields are available for read-only access:

Attribute Notes
$jconfig->{app_name} Name of Jarvis application.
$jconfig->{cgi} The CGI object for this CGI request.
$jconfig->{username} Current Logged-In Username or ''.
$jconfig->{group_list} Current Logged-In Group List or ''.
$jconfig->{logged_in} 0/1 are we logged in?
$jconfig->{error_string} Login error message if not logged-in.
$jconfig->{debug} 0/1 is debug tracing enabled?
$jconfig->{dump} 0/1 is dump tracing enabled?
$jconfig->{format} json/json.rest/xml/csv/xlsx/etc…
$jconfig->{action} select/insert/update/delete.
$jconfig->{dataset_name} Name of top-level Dataset implemented by this request.
$jconfig->{dataset_type} Type of top-level Dataset implemented by this request (i/s/e/p).

The $jconfig object is also required as a parameter for invoking Jarvis services such as the Jarvis::Error::debug and Jarvis::Error::dump methods.

Note: The $user_args parameter has NOT been checked for safety.It is user-supplied values and must be treated with suspicion.

Note: The dataset_type is either i = Internal, s = SQL, e = Exec, p = Plugin.

Output & Headers

Jarvis offers support for add_headers, filename_parameter and default_parameter handling for plugin datasets identical to exec datasets.

Exception Handling

To handle an exception in your plugin, simply call die. You may optionally set an explicit HTTP status to return. Otherwise Jarvis will return a 500 Internal Server Error.

$jconfig->{status} = '404 Not Found';
die "Plugin cannot continue, moon not found in expected phase.\n";

Note: The use of the newline escape \n at the end of the error. The newline at the end of the error will suppress the default Perl behavior of including the location of the error (file and row number). Normally it would not be appropriate to include the file and line number of the error when explicitly calling die, and in this manner it can be removed.

Getting Dataset Content with fetch_rows

A plugin may often wish to perform complex calculations and combine multiple datasets in non-standard ways. To support this, Jarvis provides an official mechanism for plugins to execute a dataset and get the results for their own purposes.

use Jarvis::Dataset;

my $rows = &Jarvis::Dataset::fetch_rows ($jconfig, $dataset_name, $user_args, $extra_href);
...

The $jconfig object is the one given to the plugin.

The $dataset_name is the name of the dataset you wish to execute.

The $user_args are the numbered and named arguments to use when performing the dataset fetch. Named parameters to the dataset must be provided here. The fetch_rows () method does not access any parameters from the $jconfig->{cgi} object. You may pass undef if you have no user args.

The $extra_href parameter should be a hash reference. Dataset hooks may add additional entries to this hash and will expect the plugin to return them as top-level parameters. You may pass undef if you do not plan to take notice of hook-requested extra top level-parameters.

The result is an ARRAY reference containing the returned rows. Noting:

Using Datasets to Store Content with store_rows

Datasets may contain store logic that plugins wish to reuse. To support this, Jarvis provides an “official” mechanism for plugins to use a dataset to store (or delete) data.

use Jarvis::Dataset;

my ($success, $message, $modified, $results) = &Jarvis::Dataset::store_rows ($jconfig, $dataset_name, $ttype, $user_args,$rows_aref, $extra_href);
...

The $jconfig object is the one given to the plugin.

The $dataset_name is the name of the dataset you wish to execute.

The $ttype is the transaction type you wish to perform - either insert, update, delete or mixed.

The $user_args are the numbered and named arguments to use when performing the dataset store. Named parameters to the dataset must be provided here. The store_rows () method does not access any parameters from the $jconfig->{cgi} object. You may pass undef if you have no user args.

The $rows_aref parameter should be an array reference for the rows that you wish to store or delete.

The $extra_href parameter should be a hash reference. Dataset hooks may add additional entries to this hash and will expect the plugin to return them as top-level parameters. You may pass undef if you do not plan to take notice of hook-requested extra top level-parameters.

$success will be 1 if all rows are processed successfully; in case of failure it will be 0.

If $success is 0, $message will contain a description of the failure.

$modified will be a count of the number of top-level rows that were modified.

$results_aref will be an ARRAY reference containing the returned results, if any.

Note:

Example Plugin

The Demo application includes a sample FileDownload plugin, configured as follows:

<jarvis>
    <app>
        <plugin dataset="FileDownload" access="**" lib="/usr/share/jarvis/demo" module="plugin::FileDownload" add_headers="yes" mime_type="text/plain">
            <parameter name="interview" value="Cross-Sectional"/>
        </plugin>
        ...

The source code is as follows:

use strict;
use warnings;

use Jarvis::Error;
use Jarvis::DB;

sub plugin::FileDownload::do {
    my ($jconfig, $user_args, %plugin_args) = @_;

    # User args includes numbered and named REST args.
    my $rest0      = (defined $user_args->{0})          ? $user_args->{0}          : '<undef>';
    my $rest1      = (defined $user_args->{1})          ? $user_args->{1}          : '<undef>';
    my $boat_class = (defined $user_args->{boat_class}) ? $user_args->{boat_class} : '<undef>';

    # User args also includes the CGI-supplied parameters.
    my $app_name  = $jconfig->{app_name};
    my $cgi_myval = (defined $user_args->{cgi_myval}) ? $user_args->{cgi_myval} : '<undef>';

    &Jarvis::Error::debug ($jconfig, "App Name: '%s'.", $app_name);
    &Jarvis::Error::dump ($jconfig, "CGI MyVal: '%s'.", $cgi_myval);

    my $interview = $plugin_args{interview} || 'Unknown';

    my $dbh       = &Jarvis::DB::handle ($jconfig);
    my $rows      = $dbh->selectall_arrayref ("SELECT COUNT(*) as count FROM boat", { Slice => {} });
    my $num_boats = $$rows[0]{count};
    my $content =
"Param|Value
App Name|$app_name
Interview|$interview
Rest 0|$rest0
Rest 1|$rest1
Boat Class|$boat_class
All Boats|$num_boats";

    return $content;
}

1;

This demonstrates:

Accessing this plugin via the following URL:

http://localhost/jarvis-agent/demo/boat/X%20Class/download/?filename=x

The output is a text file x.txt with content similar to the following:

Param|Value
App Name|demo
Interview|Cross-Sectional
Rest 0|boat
Rest 1|X Class
Boat Class|X Class
All Boats|45