Hook Modules
The hook
configuration entry allows you to define an application-custom module containing methods which will be invoked at key points during processing.
Note:
- A
fetch
request is a datasetselect
operation. - A
store
request is a datasetinsert
/update
/delete
operation.
Hooks can be defined globally and/or for individual datasets. All global hooks are loaded and invoked before all dataset-specific hooks.
Here is the Global Hook invocation matrix:
Global Hook | __status |
__habitat |
__login |
__logout |
Exec | Plugin | Fetch | Store |
---|---|---|---|---|---|---|---|---|
start |
YES | YES | YES | YES | YES | YES | YES | YES |
return_status |
YES | |||||||
return_fetch |
YES | |||||||
return_store |
YES | |||||||
finish |
YES | YES | YES | YES | YES | YES | YES | YES |
after_login |
YES | YES | YES | YES | YES | YES | YES | YES |
before_logout |
YES | |||||||
pre_connect |
YES | YES | YES | YES | YES | YES | YES | YES |
dataset_pre_fetch |
YES | |||||||
dataset_fetched |
YES | |||||||
dataset_pre_store |
YES | |||||||
dataset_stored |
YES | |||||||
before_all |
YES | |||||||
after_all |
YES | |||||||
before_one |
YES | |||||||
after_one |
YES |
Note: The after_login
hook is only actually called when:
- The client did not provide a valid session ID.
- The client did provide enough information to be logged-in during this request.
The Dataset Hook invocation matrix is as follows:
Global Hook | __status |
__habitat |
__login |
__logout |
Exec | Plugin | Fetch | Store |
---|---|---|---|---|---|---|---|---|
start |
YES | YES | ||||||
finish |
YES | YES | ||||||
dataset_pre_fetch |
YES | |||||||
dataset_fetched |
YES | |||||||
dataset_pre_sore |
YES | |||||||
dataset_stored |
YES | |||||||
before_all |
YES | |||||||
after_all |
YES | |||||||
before_one |
YES | |||||||
after_one |
YES |
Note that:
- You may implement none, some, or all hook methods in your hook module.
- All implemented hook methods must all return
1
. - There is no way for a hook to stop processing, other than to call
die
. - If an SQL error occurs during dataset updates, any following
before_one
,after_one
andafter_all
hook calls will be skipped. Only thefinish
hook call will be invoked. - If multiple
<hook>
sections are defined in the application XML file, then at the hook point, the corresponding method from all defined hook classes will be called sequentially in the order that they are listed.
Hook Configuration
The configuration for a hook
element is as follows:
Attribute | Default | Notes |
---|---|---|
lib |
(none) | This is an additional directory to be optionally added to the @INC path when loading this module.If the 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 . |
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 behaviour. |
Global Per-Query Hook Points
The Global Per-Query hook points are:
Hook | Notes |
---|---|
GLOBAL start |
The start hook method on global hooks is called when the global hook module is first loaded. No dataset analysis has been performed yet. No database transaction is open. Login check has not yet occurred. Arguments are: • $jconfig • $hook_parameters_href $jconfig is the internal Jarvis configuration object containing the query context. Refer to Plugin Datasets for more information.$hook_parameters_href is a hash containing the name and value from any <parameter> tags configured for this hook in the application XML. |
GLOBAL return_status |
This global hook method is called only for __status requests.It is called just before the status result is encoded to JSON/XML. The hook may do one or more of the following: 1. Add some extra root level parameters (by modifying $extra_href) 2. Perform a custom encoding into text (by setting $return_text) Arguments are: • $jconfig • $hook_parameters_href • $extra_href • $return_text_ref $extra_href is a reference to a hash of name/value mappings all of which will be added as root level parameters to the JSON object or XML response object that is encoded and returned to the client.$return_text_ref is a reference that the plugin may set to a non-empty text string if it wishes to override the default JSON/XML encoding that would otherwise be performed by Jarvis. In this case the hook is entirely responsible for encoding the entire JSON/XML result. |
GLOBAL return_fetch |
This global hook method is called only for fetch (I.e. data select ) requests.It is called at the end of the fetch sequence, just before the returned dataset results are encoded to JSON/XML. The hook may do one or more of the following: 1. Add some extra root level parameters (by modifying $extra_href ).2. Alter the the returned data structure (by modifying $return_object ).3. Perform a custom encoding into text (by setting $return_text_ref) .Arguments are: • $jconfig • $hook_parameters_href • $user_args_href • $results_aref • $extra_href • $return_text_ref $user_args_href is the hash of CGI parameters plus numbered and named RESTful args that were used by the top-level dataset.$rows_aref is the array of rows returned from the top level dataset query. May included nested child dataset arrays. |
GLOBAL return_store |
This global hook method is called only for store (I.e. data insert /update /delete ) requests. It is called at the end of the stored sequence, just before the results of the store operation(s) are encoded to JSON/XML/CSV/XLSX.The hook may do one or more of the following: 1. Add some extra root level parameters (by modifying $extra_href )2. Modify the returned content (by modifying $results_aref )3. Perform a custom encoding into text (by setting $return_text_ref )Arguments are: • $jconfig • $hook_parameters_href • $user_args_href • $results_aref • $extra_href • $return_text_ref $results_aref is the array of returned information that will be passed back to the client. There is one array element for each requested change. Each of these is a HASH with the following elements:• success → 0 /1 flag did this update succeed?• message → Error message if not success.• modified → Number of modifications associated with this change.• returning → Array of returning values from this change. |
GLOBAL finish |
The finish hook method on global hooks is called after processing is completed for any operation, and the response has been sent to the client. Any database transaction associated with the dataset is now finished. The hook module should use this hook only for clean-up and/or auditing. Arguments are: • $jconfig • $hook_parameters_href |
Global Utility Hook Points
The Global Utility hook points are:
Hook | Notes |
---|---|
GLOBAL after_login |
This global hook method is called only when Jarvis successfully creates a new, logged-in session. It allows the hook module to perform additional login processing, e.g. recording first/last login times. Also, the hook module may create additional safe variables which will be stored in the session and available to all interactions on this session.Arguments are: • $jconfig • $hook_parameters_href • $additional_safe_href $additional_safe_href is a hash of safe parameters which the hook module may extend. All safe parameter names must begin with a __ double underscore prefix. These changes will affect all requests in the newly created session. |
GLOBAL before_logout |
This global hook method is called just before the session is deleted from an explicit __logout dataset request.The hook cannot prevent the logout, however it may perform auditing functions. Arguments are: • $jconfig • $hook_parameters_href |
GLOBAL pre_connect |
This global hook method allows you to modify the database connection string at the time of connection. This may be useful e.g. if different login users have different, private database instances. Arguments are: • $jconfig • $hook_parameters_href • $dbname • $dbtype • $dbconnect_ref • $dbusername_ref • $dbpassword_ref • $dbh_attributes_href $dbname is the identifier for the database within the Jarvis configuration file. E.g. default .$dbtype is the key dbi or sdp used within the Jarvis configuration file to distinguish between DBI and other database mechanisms.$dbconnect_ref is the DBI or SDP connection string that has been determined. This may be modified by the hook.$dbusername_ref is the configured username. The hook may modify.$dbpassword_ref is the configured password. The hook may modify.$dbh_attributes_href is the hash of additional database connection attributes for this database type/name as read from the Jarvis configuration file. The hook may modify.Note: Currently there must be an existing <database> entry in the Jarvis configuration file before this hook is invoked. If the configuration file does not contain an entry for the requested database type /dbname then an error will be raised and the hook is not invoked. |
Per-Dataset Hook Points
The Per-Dataset hook points are:
Hook | Notes |
---|---|
DATASET start |
For per-dataset hooks, the start hook method is invoked when the dataset configuration is loaded, before any dataset security checking occurs. However, the user security has been completed and any login process will have taken place. Dataset hooks receive an additional $dsxml parameter when they are called.Arguments are: • $jconfig • $hook_parameters_href • $dsxml $dsxml is a Lib::XML object containing the dataset’s XML definition. |
GLOBAL/DATASET dataset_pre_fetch |
This global or per-dataset hook method is called only for fetch (select ) requests. It is called before the SQL select statement is constructed.Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_params_href $safe_params_href is the hash of safe variables, indexed REST args and named REST args that apply to all rows. The hook may modify values in $safe_params_href to change the input parameters to the select statement. |
GLOBAL/DATASET dataset_pre_store |
This global or per-dataset hook method is called only for store (insert /update /delete /mixed ) requests. It is called before the SQL statements are constructed.Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_params_href • $rows_aref The hook may modify values in $safe_params_href to change the input parameters to the store statements.$rows_aref is a reference to the array of row changes to be stored. The hook may change these parameters and may also add/remove rows. |
GLOBAL/DATASET before_all |
This global or per-dataset hook method is called after Jarvis has loaded the dataset configuration. It is called after the transaction begins. It is called before invoking the <before> SQL statement in the dataset XML file. It is called even if there is no <before> SQL statement.Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_params_href • $fields_aref $fields_aref is the array of user change objects submitted for this request. Changes to values in this array will be reflected in the subsequent insert /update /delete operations.Changes to $safe_params_href will affect only the <before> SQL. |
GLOBAL/DATASET after_all |
This global or per-dataset hook method is called after invoking the <after> SQL statement in the dataset XML file. It is called even if there is no <after> SQL statement. The transaction is not yet committed.Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_params_href • $fields_aref • $results_aref $results_aref is a reference to the returned row objects that will be encoded into JSON or XML. Changes to this objects in this array will be represented in the data returned to the client. |
GLOBAL/DATASET dataset_fetched |
This global or per-dataset hook method is called only for fetch (select ) requests. It is called after the SQL select is performed.The hook may do one or more of the following: 1. Add some extra scalar parameters (by modifying $extra_href )2. Modify the returned content (by modifying $rows_aref )Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_params_href • $rows_aref • $extra_href • $column_names_aref $rows_aref is a reference to the array of objects fetched as a result of the executed SQL. This is the data that will be encoded into JSON or XML. Changes to objects in this array will be represented in the data returned to the client.You must take care with $extra_href when using nested datasets, as child datasets may conflict with parent datasets if they are both setting return global attributes.$column_names_aref is a reference to the array of all the column names returned by the SQL query. |
GLOBAL/DATASET dataset_stored |
This global or per-dataset hook method is called only for store (update /insert /delete ) requests. It is called after all SQL actions have been performed (including child datasets). It is called even in the case of store failure.The hook may do one or more of the following: 1. Add some extra scalar parameters (by modifying $extra_href )2. Modify the returned content (by modifying $rows_aref )3. Change the success behaviour. Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_params_href • $results_aref • $extra_href • $success_ref • $message_ref $results_aref is the same format as described for the return_store hook.$success_ref is a reference to a success indicator with value 0 or 1 . The hook may modify this value.$message_ref is a reference to the error message in the case of store failure. The hook may modify this value. The hook may examine this value and determine to return a non-200 HTTP status (e.g. by assigning $jconfig->{status} and calling die ).This hook is called even in the case where a store row fails and the transaction is rolled-back. You must take care with $extra_href when using nested datasets, as child datasets may conflict with parent datasets if they are both setting return global attributes. |
DATASET finish |
The finish hook method on dataset hooks is called after processing is completed for the dataset, but before the result is returned to the client. It is called before any global return_fetch or return_store hooks are invoked.Any database transaction associated with the dataset is now finished. The hook module should use this hook only for clean-up and/or auditing. This hook is not suitable for modifying the content returned to the client. Please use a global return_fetch or return_store hook method instead.Arguments are: • $jconfig • $hook_parameters_href • $dsxml |
Per-Row Hook Points
Hook | Notes |
---|---|
GLOBAL/DATASET before_one |
This global or per-dataset hook method is called after Jarvis has assembled all parameters in order to execute a single insert/update/delete statement. It is called before the actual execution of the row modification SQL. Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_row_params_href $safe_row_params_href is the hash of variables to be bound to the single SQL row update. Changes to values in this hash will be reflected in the database for this row update only. |
GLOBAL/DATASET after_one |
This global or per-dataset hook method is called after Jarvis has executed a single insert /update /delete statement. It is called after any returning row result has been fetched. Arguments are: • $jconfig • $hook_parameters_href • $dsxml • $safe_row_params_href • $row_result_href $safe_row_params_href is the hash of variables previously bound to the single SQL row update. Changing values in this hash will have no effect.$row_result_href is the contents of any returning row. The hook code may change values in this hash and the change will be reflected in the corresponding object returned to the client. |
Sample Global Hook Template
The following empty module should help you get your first Global Hook module under way. You may safely delete any hook methods you do not wish to implement.
use strict;
use warnings;
# PER QUERY GLOBAL HOOKS
# Global "start" hook.
# CALLED: After all Jarvis setup is complete.
sub hook::ExampleGlobalHook::start {
my ($jconfig, $hook_params_href) = @_;
return 1;
}
# Global "return_status" hook.
# CALLED: Before returning result of a "__status" request.
sub hook::ExampleGlobalHook::return_status {
my ($jconfig, $hook_params_href, $extra_href, $return_text_aref) = @_;
return 1;
}
# "return_fetch" hook.
# CALLED: Before returning result of a “fetch” request.
sub hook::ExampleGlobalHook::return_fetch {
my ($jconfig, $hook_params_href, $user_args_href, $rows_aref,
$extra_href, $return_text_aref) = @_;
return 1;
}
# "return_store" hook.
# CALLED: Just before returning result of a "store" request.
sub hook::ExampleGlobalHook::return_store {
my ($jconfig, $hook_params_href, $user_args_href, $results_aref,
$extra_href, $return_text_aref) = @_;
return 1;
}
# "finish" hook.
# CALLED: After Jarvis processing is complete, at cleanup time.
sub hook::ExampleGlobalHook::finish {
my ($jconfig, $hook_params_href) = @_;
return 1;
}
# UTILITY GLOBAL HOOKS
# "after_login" hook.
# CALLED: After first login for the session.
sub hook::ExampleGlobalHook::start {
my ($jconfig, $hook_params_href, $additional_safe_href) = @_;
return 1;
}
# "before_logout" hook.
# CALLED: Before explicit session logout by the client
sub hook::ExampleGlobalHook::before_logout {
my ($jconfig, $hook_params_href) = @_;
return 1;
}
# "pre_connect" hook.
# CALLED: Before first connecting to each database.
sub hook::ExampleGlobalHook::pre_connect {
my ($jconfig, $dbname, $dbtype, $dbconnect_ref, $dbusername_ref,
$dbpassword_ref, $parameters_href) = @_;
return 1;
}
# PER-DATASET GLOBAL HOOKS
# "dataset_pre_fetch" hook.
# CALLED: ("fetch" only) Before constructing the fetch request.
sub hook::ExampleGlobalHook:: dataset_pre_fetch {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href) = @_;
return 1;
}
# "dataset_pre_store" hook.
# CALLED: ("store" only) Before constructing the store request.
sub hook::ExampleGlobalHook:: dataset_pre_store {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href,
$rows_aref) = @_;
return 1;
}
# "before_all" hook.
# CALLED: ("store" only) After transaction begins. Before any "before" SQL.
sub hook::ExampleGlobalHook::before_all {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href,
$fields_aref) = @_;
return 1;
}
# "after_all" hook.
# CALLED: ("store" only) After any "after" SQL. Before transaction ends.
sub hook::ExampleGlobalHook::after_all {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href, $fields_aref,
$results_aref) = @_;
return 1;
}
# "dataset_fetched" hook.
# CALLED: ("fetch" only) After fetching results array for a single dataset.
sub hook::ExampleGlobalHook::dataset_fetched {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href, $rows_aref,
$extra_href, $column_names_aref) = @_;
return 1;
}
# "dataset_stored" hook.
# CALLED: ("store" only) After storing results array for a single dataset.
sub hook::ExampleGlobalHook::dataset_stored {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href,
$results_aref, $extra_href, $success_ref, $message_ref) = @_;
return 1;
}
# PER-ROW GLOBAL HOOKS
# "before_one" hook.
# CALLED: ("store" only) Before we execute the row insert/update/delete SQL.
sub hook::ExampleGlobalHook::before_one {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href) = @_;
return 1;
}
# "after_one" hook.
# CALLED: ("store" only) After insert/update/delete and "returning" extraction.
sub hook::ExampleGlobalHook::after_one {
my ($jconfig, $hook_params_href, $dsxml, $safe_params_href,
$row_result_href) = @_;
return 1;
}
1;
Sample Dataset Hook Template
A dataset hook module may use any of the Per-Dataset or Per-Row hooks listed above.
Note: The start
hook for a Dataset has the additional $dsxml
parameter available.
use strict;
use warnings;
# PER-DATASET DATASET HOOKS
# Dataset "start" hook.
# CALLED: ("fetch" AND "store") Just after loading dataset config.
sub hook::ExampleGlobalHook::start {
my ($jconfig, $hook_params_href, $dsxml) = @_;
return 1;
}
# Others: Same as the Global Hooks of the same name.
# sub dataset_pre_fetch ()
# sub dataset_pre_store ()
# sub before_all ()
# sub after_all ()
# sub dataset_fetched ()
# sub dataset_stored ()
# PER-ROW DATASET HOOKS
# Same as the Global Hooks of the same name.
# sub before_one ()
# sub after_one ()
1;
Exception Handling
To handle an exception in your hook, 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 "Hook cannot continue, moon not found in expected phase.\n";
Note: The use of the newline escape character \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.
Custom Headers
You may need to add headers to your dataset return. To do this Jarvis offers the add_http_header
function.
&Jarvis::Config::add_http_headers ($jconfig, { ‘key’ => ‘value’ };
This will then be printed along side the dataset headers. It is not possible to override existing headers only add new ones.