Developers > Programming > Introduction to the ExSite Kernel

Introduction to the ExSite Kernel

The ExSite kernel consists of the libraries that perform the core services of ExSite. These services include:

  • interacting with database(s)
  • user authentication and security
  • web page generation and content handling
  • input/output handling
  • form generation and processing
  • reporting and data formatting
  • managing web protocols (HTML, HTTP, URIs, RSS, cookies)
  • system configuration and initialization
  • data handling (structures, caches, objects, specialized data types)
  • searching
  • translations
  • interacting with plug-in modules
There is a lot of area covered in the kernel, and this document does not cover all of it. This is more of an introduction to help you navigate through the kernel and understand some of the basic concepts.

Index of Modules

The ExSite Kernel files are located in cgi-bin/ExSite. Here is a list of important Perl modules you will find here, and what they do:

Fundamentals

  • Base.pm - base class inherited by all other ExSite classes. This provides basic programming features such as error handling, logging,and handlers (see below).
  • Config.pm - defines base system configuration and global variables, and includes subroutines that interact with these.
  • Util.pm - miscellaneous routines that depend on other ExSite Libraries.
  • Misc.pm - miscellaneous routines that do not depend on any other ExSite libraries.

Database Management

  • Form.pm - class that manages interaction with databases via HTML forms. (Inherits from Report.pm)
  • Report.pm - class that manages display of fields, records, and groups of records from the database. (Inherits from DB.pm)
  • DB.pm - abstracted database class that provides a standard set of tools to interact with an arbitrary database engine. (Inherits dynamically from one of the installed database engine classes.)
  • SQL.pm - a MySQL database engine.
  • Text.pm - a plain-text (tab-delimited file) database engine.
  • DBmap.pm - class that interacts with the database map, which describes and defines various database rules and behaviours used for automatic form processing.
  • Auth.pm - implements the standard ExSite security framework, to manage access to arbitrary records in the database, based on the user's access level and administrator keys.
  • Attribute.pm - a class that allows the database schema to be extended by adding arbitrary key/value pairs to any database record.

Content Management

  • Section.pm - class to manage websites and website sections
  • Page.pm - class to manage web pages, templates, and libraries
  • Content.pm - class to manage individual content objects
  • ContentData.pm - class to manage content revisions
  • ContentBase.pm - base class for above content management classes
  • Search.pm - generate and query search indexes

HTML Formatting

  • ML.pm - class that manages markup languages like HTML and XML
  • ReportBuilder.pm - class to assemble tabular reports.
  • FormBuilder.pm - class to generate forms with built-in validation.
  • Wizard.pm - class to build multi-screen forms with branching logic.
  • Dialog.pm - class used in the generation of ExSite dialog boxes.
  • URI.pm - class used for parsing and assembling web addresses (URLs)

Other Data Handling

  • Input.pm - class to manage web inputs (GETs, POSTs, and PATH_INFO)
  • Image.pm - class to handle images, including scaling and thumbnailing
  • Cookie.pm - class to handle the cookies that are known for a visitor
  • Crypt.pm - 128-bit encryption and decryption
  • Cache.pm - database cache.
  • Excel.pm - tools for generating Excel-formatted exports.
  • Session.pm - interact with the user's session data.
  • Store.pm - low-level persistent data system that is used by Cache.pm, Session.pm, and others.
  • Tree.pm - manage hierarchical data.
  • Object.pm - base class for objectifying database records
  • Time.pm - handle and compare times and dates in various formats.

Global Variables

The following global variables are defined in ExSite::Config, and are automatically exported to all ExSite code.

%config

System configuration settings are stored in the %config global variable, which is initialized with defaults in Config.pm. The %config variable is a nested hash which contains parameters that are often bundled into groups, for example:

$config{parameter}
$config{group}{parameter}
$config{group}{subgroup}{parameter}

To change configuration settings in your local installation, you can specify your preferred values in the file exsite.conf (place this file in cgi-bin, or cgi-bin/conf). The format to change the parameters above would be:

parameter = value
group.parameter = value
group.subgroup.parameter = value

There is no need to quote values; it will take in everything from the first non-whitespace character after the "=" to the end of the line.

To create parameter groups, simply use them as above. ExSite will automatically create the group as needed. To create arrays of values, define the first value as above, then add more values to it, like so:

group.subgroup.parameter += anothervalue

In your code, this will be represented by a structure like:

$config{group}{subgroup}{parameter} = [ "value", "anothervalue" ];
You can inspect Config.pm to get a complete list of system configuration settings. (They are fairly well commented.) You can also obtain a quick listing of all configuration parameters with their current settings using the utility script printconf.pl, which is distributed in the bin directory of the ExSite Base distribution. This will print out the over 400 known configuration settings and their values in your installation.

%share

This holds all shared data pertaining to the current request. It is empty at the start of each request, and is populated with various shareable data as the request is processed. This is one of the more important methods of inter-module communication in ExSite. Some examples of the shareable data that the kernel places in %share:

$share{DB} - the default database object
$share{Page} - the Page object for the page that is currently being built/viewed
$share{identity} - some information about the current user
$share{input} - cache of input data

You can also place anything you like into %share, but take care to give it a unique key to avoid overwriting other data.

%session

This holds data that is unique to the current visitor. If session management is enabled, this data will persist between requests, which means if you place a value in this hash, you can still expect to find it there on a different page view at a later time. However, sessions have a limited lifetime, and will be automatically cleared when this time expires.

You can place any key/value pairs into this hash, including complex structures. ExSite does not make use of %session in its default configuration, so session management is not enabled by default. Some special set ups will make use of it, however. For instance, if you switch to the session method of authentication. ExSite will store the user's authentication information in their session hash, so that the database does not have to be consulted on every page view. Shopping cart systems will also use the session to collect the cart data.

If session management is not enabled, this variable will be cleared on each new request, much like %share. There is no harm to using %session if you are not using session management, but session data will not have any persistence, and those optional modules that expect sessions to persist will not work.

%store

This holds system-wide data that persists between processes. This is used to implement various low-level features, including database caches, file caches, and sessions. Persistent data is not enabled by default, but ExSite will still work without it. However, it will have to refetch/rebuild data on every page request. Enabling the persistent data store should give a significant performance boost.

%msg

This holds system messages in translation, so that ExSite can be localized to languages other than English. To output a system message, use something like:
return $msg{"Permission denied - please log in."};
If you have defined a language preference, and a translation exists for this message, that translated message will be used. If no translation exists, or you are using the default language configuration, then you will get the message as it is coded. If you do not use this technique for handling system messages, and simply output a string in Engligh (or any other language), your messages will still work, but will not benefit from the built-in internationalization features of ExSite.

The SysMsg plug-in can be used to manage your system message translations.

Plug-in Module Configuration

Kernel configuration parameters are written into exsite.conf, but plug-in web application modules may have their own configuration data that is read from separate files.

When ExSite dynamically loads a plug-in module named Foo, it looks for a matching configuration file in cgi-bin/conf/Foo.conf. The parameters in this file are loaded into $config{Foo}{...}. For example, if cgi-bin/conf/Foo.conf contains the parameter:

group.parameter = 10

then this will be loaded into $config{Foo}{group}{parameter}. This is equivalent to the following written into the main config file, exsite.conf:

Foo.group.parameter = 10

Plug-in modules do not have to define their own configuration files or parameters, so the presence of a plug-in module does not ensure that these configuration categories will exist.

myConfig.pm

The file cgi-bin/myConfig.pm is automatically loaded by ExSite when it starts up. As distributed, this file contains only a few code stubs that do nothing much. However, the local site can add their own kernel customization code into this file, using various hooks that the system provides for this purpose. It is best practice to keep your customizations restricted to this file, so that the kernel itself can be easily upgraded as needed.

The primary hooks are:

&my_exsite_init()

This is called when ExSite starts up and begins to serve a new request, after the basic system initialization (&exsite_init) is complete. The local site can perform any special initializations that it needs at this time.

&my_exsite_close()

This is called when ExSite finishes a request, and is preparing to close the connection. The local site can perform any special clean-up that it needs at this time.

&my_handlers()

All other hooks into the kernel are provided by handlers. At various places in the system where it is feasible for a local site to override default system logic and use customized code instead, ExSite will check to see if there is a handler installed for that function. If so, the handler will be executed. If not (or if the handler runs, but decides to do nothing), ExSite will resume with the default system code. See the section on handlers, below, for more information.

Every hook for a handler has a unique name. For example, the authentication step of validating a user identity has a hook called "authenticate". If the local site has installed a handler under this name, that code will be used preferentially over the system "authenticate" code.

Site-specific custom handlers are installed by the &my_handlers routine. This routine is used to automatically register your handlers with every ExSite object that is created. Note that &my_handlers always thinks that it is a method of that object's class, so you can use OOP calling conventions to register the handler in the object, eg:
sub my_handlers {
my $self = shift;
$self->handler("authenticate",\&my_custom_authenticate_function);
}
Your custom function should be included in myConfig.pm. It will execute as if a member of the calling object's class.

Handlers

ExSite contains many hooks for handlers at various places in the Kernel and also in some plug-ins. Each hook has a unique name. If you register a handler routine for that name, your special routine will be executed whenever that hook is reached during execution.

Handlers should return a single scalar value. By convention they return undef if they abort (such as if the handler decides that it should not do anything special in this case). In that case, ExSite will proceed with the regular system code. However, if the handler returns a defined value, then ExSite knows that it executed and performed its special function. ExSite then has the option of not executing the regular system code.

Multiple handlers can be registered under a given hook's name. In this case, each handler will be executed in turn (in the order in which they were registered) until one returns a defined value, indicating that it executed. At that point, no further handlers under that hook will execute.

Handlers may accept any number of parameters as input. Because they typically substitute for standard system routines, they usually take the same parameter list as their corresponding system routine. You should always check the code to verify how handlers are called, and how their output is processed.

Example

The kernel method that displays a datum taken from an ExSite-managed database is ExSite::Report::show_data(). It accepts up to 4 parameters: the table name, the column name, the data value, and optionally the record id. ExSite determines how to display the data value based on the datatype of this column and other factors. This routine has a hook called "show_data" that can be used to override the system rules for displaying data. If you needed to override this logic in particular cases, you would create a handler, for instance:

sub my_show_data {
my ($this,$table,$column,$data,$id) = @_;

# special display logic for internet users
if ($ENV{REMOTE_ADDR} !~ /^192\.168/) {
# user is not on our LAN -
# block the display of all columns from "secure_data" table
if ($table eq "secure_data") {
return "n/a";
}
}

# in all other cases, return undef to use default kernel logic
return undef;
}

In this example, we override the ExSite::Report::show_data() logic in the case where the system is showing data from one particular sensitive table to a user who is not on our LAN. In this case, the system always returns "n/a" as the data value. Otherwise the handler returns undef, which tells ExSite that the handler aborted and ExSite should proceed with its normal logic to display the requested data.

The above handler would be registered in &my_handlers using a call like this:

$self->handler( "show_data", \&my_show_data );

Hooks

If you are writing some general-purpose code, and recognize that some function could be replaced with a handler, it is easy to insert a hook. The following template is fairly typical:
sub foo_bar {
my ($self,$input) = @_;

# hook to execute a handler if one exists
my $stat = $self->run_handler("foo_bar",$input);
return $stat if (defined $stat);

# resume normal execution
...
}
In this example, we try to run any handlers registered under the "foo_bar" hook. If none exist, or the ones that are registered do not take any action, the hook returns an undef, and we execute our regular code. If, on the other hand, an actual return value is received back, we know that our handlers executed and did something. In this case we use that return value as our own return value, and do not bother to execute the default code. In practice, you can do anything you like with the return value.

List of Hooks

This is a list of hooks in the ExSite kernel libraries as of v3.6. Other hooks may also exist in other CGI programs or plug-in modules.

approve allow the user to perform some database function
authenticate confirm the user's claimed identity 
authorize grant the user a certain level of access 
build_form generate an HTML form based on data that has been provided to FormBuilder 
cancel_form executed when user hits a cancel button on a form 
crypt_key obtain encryption key
decrypt decrypt some ciphertext
delete_key delete a single record 
do_login
login a user 
encrypt
encrypt some plaintext
fetch_metadata obtain metadata for an object 
find_ancestor find the root record in a tree of record relationships 
find_owner find the user who has authority over a data record
group_owns find the group who has authority over a data record 
identify determine who the user is claiming to be 
import_record modify data that is about to be imported into the database 
input_column generate an HTML input field corresponding to a database column
input_date generate an HTML date input field
input_exsite generate an HTML input field corresponding to an ExSite datatype 
is_member test if user is a member of a section or site 
login validate a login/password pair 
login_form generate an HTML form for the user to log in 
login_reminder_form generate an HTML form for the user to get a password reminder or reset 
login_temp log the user in for the current request, but do not let the identity persist 
log_login do something when a successful login occurs 
lookup find the user information corresponding to the user's claimed identity 
my_name return the user's actual name 
page_authorize allow the user to view a web page 
page_get_urlget the URL for a web page 
post_delete
do something after a database deletion 
post_insert do something after a database insertion 
post_make_content do something after a new content object is created 
post_make_page do something after a new page is created 
post_make_section do something after a new section is created 
post_select do something after records have been fetched 
post_update do something after records have been updated
pre_delete do something before a database deletion 
pre_insert do something before a database insertion 
pre_make_content do something before a new content object is created
pre_make_page do something before a new page is created
pre_make_section do something before a new section is created
pre_select do something before records have been fetched
pre_update do something before records have been updated
report_generic
format an HTML report based on data collected by ReportBuilder
report_links create links/tools in database reports  
report_links_extra append extra links/tools in database reports 
report_title compose a title for automatically generated database reports
select_foreign_key fetch the list of records to be selected from when building a select input to point to a foreign key 
select_foreign_key_label create the selector strings used to select foreign keys in select inputs
show_data display any datum taken from the database
trash_r recursively move records to the trash
user_owns determine if the user owns a data record
validate determine if data in a recordhash is valid and can be dispatched to the database
validate_column determine if a datum corresponding to a particular database column is valid and can be dispatched to the database  
validate_datatype determine if a datum matches the expected format for its datatype 

Note that there is one handler registered by default in the standard ExSite configuration. It is registered for the "select_foreign_key" hook, and is used for selecting foreign key relations in the CMS tables.

Topics