Development & IT > 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
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-deliminted 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 registered 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_url | get 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.