NAME
App::Context - An application framework for web applications, command-line programs, server programs, and web services
SYNOPSIS
# ... official way to get a Context object ...
use App;
$context = App->context();
$context->dispatch_events(); # dispatch events
$conf = $context->conf(); # get the configuration
# any of the following named parameters may be specified
$context = App->context(
context_class => "App::Context::CGI",
conf_class => "App::Conf::File", # or any Conf args
);
# ... alternative way (used internally) ...
use App::Context;
$context = App::Context->new();
DOCUMENT STATUS
This documentation is out of date and needs review and revision.
Please start with the App::quickstart document.
DESCRIPTION
A Context class models the environment (aka "context") in which the current process is running.
The role of the Context class is to abstract the details of the various runtime environments (or Platforms) (including their event loops) so that the basic programming model for the developer is uniform.
Since the Context objects are the objects that initiate events in the App-Context universe, they must be sure to wrap those event handlers with try/catch blocks (i.e. "eval{};if($@){}" blocks).
The main functions of the Context class are to
* load the Conf data,
* dispatch events from the Context event loop, and
* manage Session data.
The Context object is always a singleton per process (except in rare cases like debugging during development).
Conceptually, the Context may be associated with many Conf's (one per authenticated user) and Sessions (one per unique session_id) in a single process (ModPerl). However, in practice, it is often associated with only one Conf or Session throughout the lifetime of the process (CGI, Cmd).
Class Group: Context
The following classes might be a part of the Context Class Group.
Class: App::Context
Class: App::Context::CGI
Class: App::Context::FCGI
Class: App::Context::ModPerl
Class: App::Context::ModPerlRegistry
Class: App::Context::PPerl
Class: App::Context::Cmd
Class: App::Context::Daemon
Class: App::Context::POE
Class: App::Context::SOAP (when acting as a SOAP server)
Class: App::Context::Gtk
Class: App::Context::WxPerl
Attributes, Constants, Global Variables, Class Variables
Master Data Structure Map
$context
$context->{debug_scope}{$class} Debugging all methods in class
$context->{debug_scope}{$class.$method} Debugging a single method
$context->{options} Args that Context was created with
$context->{used}{$class} Similar to %INC, keeps track of what classes used
$context->{Conf}{$user} Info from conf file
[$context->{conf}]
$conf->{$type}{$name} Read-only service conf
$context->{sessions}{$session_id}
[$context->{session}]
$session->{store}{$type}{$name} Runtime state which is stored
$session->{cache}{$type}{$name} Instances of services
Constructor Methods:
new()
The App::Context->new() method is rarely called directly. That is because a $context should always be instantiated by calling App->context(). This allows for caching of the $context as a singleton and the autodetection of what type of Context subclass should in fact be instantiated.
* Signature: $context = App->new($named);
* Signature: $context = App->new(%named);
* Param: context_class class [in]
* Param: conf_class class [in]
* Param: conf_file string [in]
* Return: $context App::Context
* Throws: Exception::Class::Context
* Since: 0.01
Sample Usage:
$context = App::Context->new();
$context = App::Context->new( {
conf_class => 'App::Conf::File',
conf_file => 'app.xml',
} );
$context = App::Context->new(
conf_class => 'App::Conf::File',
conf_file => 'app.xml',
);
Protected Methods:
The following methods are intended to be called by subclasses of the current class (or environmental, "main" code).
_init()
The _init() method is called from within the standard Context constructor. The _init() method in this class does nothing. It allows subclasses of the Context to customize the behavior of the constructor by overriding the _init() method.
* Signature: $context->_init($options)
* Param: $options {} [in]
* Return: void
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$context->_init($options);
Public Methods: Services
service()
The service() method returns a named object of a certain service type.
* Signature: $service = $context->service($type);
* Signature: $service = $context->service($type,$name);
* Signature: $service = $context->service($type,$name,%named);
* Param: $type string [in]
* Param: $name string [in]
* Return: $service App::Service
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$user = $context->service("SessionObject","db.user.spadkins");
$gobutton = $context->service("SessionObject","gobutton");
There are many services available within an App-Context application. Each service is identified by two pieces of information: it's type and its name.
The following service types are standard in App-Context. Others can be developed by deriving a class from the App::Service class. All service types must start with a capital letter.
* Serializer
* CallDispatcher
* MessageDispatcher
* ResourceLocker
* SharedDatastore
* Authentication
* Authorization
* SessionObject
Within each service type, each individual service is identified by its name. The name of a service, if not specified, is assumed to be "default".
Whenever a service is requested from the Context via this service() method, the service cache in the Session is checked first. If it exists, it is generally returned immediately without modification by the named parameters. (Parameters *are* taken into account if the "override" parameter is supplied.)
If it does not exist, it must be created and stored in the cache.
The name of a service, if not specified, is assumed to be "default".
The named parameters (%named or $named), if supplied, are considered defaults. They are ignored if the values already exist in the service conf. However, the additional named parameter, "override", may be supplied. In that case, all of the values in the named parameters will accepted into the service conf.
Every service (i.e. $conf->{Repository}{default}) starts as a simple hash which is populated with attributes from several complementary sources. If we imagine that a service is requested with type $type and name $name, we can envision the following additional derived variables.
$type = "Repository";
$name = "sysdb";
$conf = $context->conf();
$repository_type = $conf->{Repository}{sysdb}{repository_type};
The following sources are consulted to populate the service attributes.
1. conf of the service (in Conf)
i.e. $conf->{Repository}{sysdb}
2. optional conf of the service's service_type (in Conf)
i.e. $conf->{RepositoryType}{$repository_type}
3. named parameters to the service() call
All service configuration happens before instantiation this allows you to override the "service_class" in the configuration in time for instantiation
serializer()
call_dispatcher()
message_dispatcher()
resource_locker()
shared_datastore()
authentication()
authorization()
session_object()
These are all convenience methods, which simply turn around and call the service() method with the service type as the first argument.
* Signature: $session = $context->session();
* Signature: $session = $context->session($name);
* Signature: $session = $context->session($name,%named);
* Param: $name string [in]
* Return: $service App::Service
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$serializer = $context->serializer();
$call_dispatcher = $context->call_dispatcher();
$message_dispatcher = $context->message_dispatcher();
$resource_locker = $context->resource_locker();
$shared_datastore = $context->shared_datastore();
$authentication = $context->authentication();
$authorization = $context->authorization();
$session_object = $context->session_object();
$value_domain = $context->value_domain();
session_object_exists()
* Signature: $exists = $context->session_object_exists($session_object_name);
* Param: $session_object_name string
* Return: $exists boolean
* Throws: <none>
* Since: 0.01
Sample Usage:
if ($context->session_object_exists($session_object_name)) {
# do something
}
The session_object_exists() returns whether or not a session_object is already known to the Context. This is true if
* it exists in the Session's session_object cache, or
(i.e. it has already been referenced and instantiated in the cache),
* it exists in the Session's store, or
(i.e. it was referenced in an earlier request in this session)
* it exists in the Conf
If this method returns FALSE (undef), then any call to the session_object() method must specify the session_object_class (at a minimum) and may not simply call it with the $session_object_name.
This is useful particularly for lightweight session_objects which generate events (such as image buttons). The $context->dispatch_events() method can check that the session_object has not yet been defined and automatically passes the event to the session_object's container (implied by the name) for handling.
Public Methods: Accessors
get_option()
* Signature: $value = $context->get_option($var, $default);
* Param: $var string
* Param: $attribute string
* Return: $value string
* Throws: <none>
* Since: 0.01
Sample Usage:
$script_url_dir = $context->get_option("scriptUrlDir", "/cgi-bin");
The get_option() returns the value of an Option variable (or the "default" value if not set).
This is an alternative to getting the reference of the entire hash of Option variables with $self->options().
get_user_option()
* Signature: $value = $context->get_user_option($var);
* Param: $var string
* Return: $value string
* Throws: <none>
* Since: 0.01
Sample Usage:
$theme = $context->get_user_option("theme");
$lang = $context->get_user_option("lang");
The get_user_option() returns the value of a user option variable. This is simply the $var attribute of the "default" session object (if it exists) or the $var attribute from the global options file.
get_auth_attrib_value()
The get_auth_attrib_value() consults the "default" Authorization service to determine the "authorized" value of a service configuration's attribute.
* Signature: $attrib_value = $self->get_auth_attrib_value($service_conf, $service_type, $service_name, $attrib);
* Param: $service_conf HASH
* Param: $service_type string
* Param: $service_name string
* Param: $attrib string
* Return: $attrib_value ANY
* Throws: <none>
* Since: 0.01
Sample Usage:
$service_type = "SessionObject";
$service_name = "foo";
$service_conf = $self->{conf}{$service_type}{$service_name};
$clone_name = $self->get_auth_attrib_value($service_conf, $service_type, $service_name, "clone");
so_get()
The so_get() returns the attribute of a session_object.
* Signature: $value = $context->so_get($session_objectname, $attribute);
* Signature: $value = $context->so_get($session_objectname, $attribute, $default);
* Signature: $value = $context->so_get($session_objectname, $attribute, $default, $setdefault);
* Param: $session_objectname string
* Param: $attribute string
* Param: $default any
* Param: $setdefault boolean
* Return: $value string,ref
* Throws: <none>
* Since: 0.01
Sample Usage:
$cname = $context->so_get("default", "cname");
$width = $context->so_get("main.app.toolbar.calc", "width");
so_set()
The so_set() sets an attribute of a session_object in the Session.
* Signature: $context->so_set($session_objectname, $attribute, $value);
* Param: $session_objectname string
* Param: $attribute string
* Param: $value string,ref
* Return: void
* Throws: <none>
* Since: 0.01
Sample Usage:
$context->so_set("default", "cname", "main_screen");
$context->so_set("main.app.toolbar.calc", "width", 50);
$context->so_set("xyz", "{arr}[1][2]", 14);
$context->so_set("xyz", "{arr.totals}", 14);
so_default()
The so_default() sets the value of a SessionObject's attribute only if it is currently undefined.
* Signature: $value = $context->so_default($session_objectname, $attribute);
* Param: $session_objectname string
* Param: $attribute string
* Return: $value string,ref
* Throws: <none>
* Since: 0.01
Sample Usage:
$cname = $context->so_default("default", "cname");
$width = $context->so_default("main.app.toolbar.calc", "width");
so_delete()
The so_delete() deletes an attribute of a session_object in the Session.
* Signature: $context->so_delete($session_objectname, $attribute);
* Param: $session_objectname string
* Param: $attribute string
* Return: void
* Throws: <none>
* Since: 0.01
Sample Usage:
$context->so_delete("default", "cname");
$context->so_delete("main-app-toolbar-calc", "width");
$context->so_delete("xyz", "{arr}[1][2]");
$context->so_delete("xyz", "{arr.totals}");
substitute()
The substitute() method substitutes values of SessionObjects into target strings.
* Signature: $context->substitute($session_objectname, $attribute);
* Param: $session_objectname string
* Param: $attribute string
* Return: void
* Throws: <none>
* Since: 0.01
Sample Usage:
$context->substitute("default", "cname");
$context->substitute("main.app.toolbar.calc", "width");
$context->substitute("xyz", "{arr}[1][2]");
$context->substitute("xyz", "{arr.totals}");
Public Methods: Miscellaneous
add_message()
The add_message() method stores a string (the concatenated list of @args) in the Context until it can be viewed by and acted upon by the user.
* Signature: $context->add_message($msg);
* Param: $msg string [in]
* Return: void
* Throws: <none>
* Since: 0.01
Sample Usage:
$context->add_message("Data was not saved. Try again.");
log()
The log() method writes a string (the concatenated list of @args) to the default log channel.
* Signature: $context->log(@args);
* Signature: $context->log($options, @args);
* Param: $options HASH [in] (named)
* Param: level integer
* Param: @args string [in]
* Return: void
* Throws: <none>
* Since: 0.01
Sample Usage:
$context->log("oops, a bug happened");
These are the standardized log levels.
0 - Context logs nothing (absolutely silent) [???]
1 - only application events [???]
2 - [default] major system-level events [standard level for operations]
3 - internal system-level events [standard level for development]
4 - internal activities [standard level for debugging internals]
5 - internal activities (inside loops) [extreme level for debugging internals]
$self->log("ERROR: send_async_event_now(): node not assigned\n"); $self->log($@);
$self->log({level=>2},"Starting Cluster Node on $self->{host}:$self->{port}\n"); $self->log({level=>2},"Stopping Cluster Node\n"); $self->log({level=>2},"Starting Server on $self->{host}:$self->{port}\n"); $self->log({level=>2},"Stopping Server.\n"); $self->log({level=>2},"Starting Cluster Controller on $self->{host}:$self->{port}\n"); $self->log({level=>2},"Stopping Cluster Controller\n");
$self->log({level=>3},"Send Event: $service_type($name).$method(@args)\n"); $self->log({level=>3},"Send Event: $method(@args)\n"); $self->log({level=>3},"$service_type $name instantiated [$service]\n"); $self->log({level=>3},"Schedule Event (" . join(",",%event) . ")\n"; $self->log({level=>3},"Caught Signal: @_\n"); }; $self->log({level=>3},"Caught Signal: @_\n"); }; $self->log({level=>3},"Caught Signal: @_\n"); }; $self->log({level=>3},"Caught Signal: @_ (quitting)\n"); $quit = 1; }; $self->log({level=>3},"Caught Signal: @_ (quitting)\n"); $quit = 1; }; $self->log({level=>3},"Caught Signal: @_ (quitting)\n"); $quit = 1; }; $self->log({level=>3},"send_message($host, $port, $message)\n"); $self->log({level=>3},"send_message($host, $port, ...) => [$response]\n"); $self->log({level=>3},"process_msg($msg)\n"); $self->log({level=>3},"process_msg: [$msg]\n"); $self->log({level=>3},"process_msg($msg)\n");
$self->log({level=>4},"Checking for scheduled events.\n"); $self->log({level=>4},"Listening on socket: timeout($sleep_interval)\n"); $self->log({level=>4},"Caught Signal: @_\n"); }; $self->log({level=>4},"Listening on socket: timeout($sleep_interval)\n"); $self->log({level=>4},"Child $pid finished [exitval=$exitval,sig=$sig]\n");
$self->log({level=>5},"Checking event: time=$time [$event->{time}, every $event->{interval}] $event->{method}().\n"); $self->log({level=>5},"Event Rescheduled: time=$time [$event->{time}, every $event->{interval}] $event->{method}().\n"); $self->log({level=>5},"Event Removed: time=$time [$event->{time}, every $event->{interval}] $event->{method}().\n");
user()
The user() method returns the username of the authenticated user. The special name, "guest", refers to the unauthenticated (anonymous) user.
* Signature: $username = $context->user();
* Param: void
* Return: string
* Throws: <none>
* Since: 0.01
Sample Usage:
$username = $context->user();
options()
* Signature: $options = $context->options();
* Param: void
* Return: $options {}
* Throws: <none>
* Since: 0.01
Sample Usage:
$options = $context->options();
The options() method returns a hashreference to all of the variable/value pairs used in the initialization of the Context.
conf()
* Signature: $conf = $context->conf();
* Param: void
* Return: $conf App::Conf
* Throws: <none>
* Since: 0.01
Sample Usage:
$conf = $context->conf();
The conf() method returns the user's conf data structure.
session()
* Signature: $session = $context->session();
* Signature: $session = $context->session($session_id);
* Param: $session_id string
* Return: $session App::Session
* Throws: <none>
* Since: 0.01
Sample Usage:
$session = $context->session();
$session = $context->session("some_session_id");
The session() method returns the current session (if no session_id is supplied). If a session_id is supplied, the requested session is instantiated if necessary and is returned.
Public Methods: Debugging
dbg()
The dbg() method is used to check whether a given line of debug output should be generated. It returns true or false (1 or 0).
If all three parameters are specified, this function returns true only when the global debug level ($App::Context::DEBUG) is at least equal to $level and when the debug scope is set to debug this class and method.
* Signature: $flag = $context->dbg($class,$method,$level);
* Param: $class class [in]
* Param: $method string [in]
* Param: $level integer [in]
* Return: void
* Throws: App::Exception::Context
* Since: 0.01
Sample Usage:
$context->dbgprint("this is debug output")
if ($App::DEBUG && $context->dbg(3));
$context->dbgprint("this is debug output")
if ($context->dbg(3));
The first usage is functionally identical to the second, but the check of the global debug level explicitly reduces the runtime overhead to eliminate any method calls when debugging is not turned on.
dbgprint()
The dbgprint() method is used to produce debug output. The output goes to an output stream which is appropriate for the runtime context in which it is called.
* Signature: $flag = $context->dbgprint(@args);
* Param: @args string [in]
* Return: void
* Throws: App::Exception::Context
* Since: 0.01
Sample Usage:
$context->dbgprint("this is debug output")
if ($App::DEBUG && $context->dbg(3));
dbglevel()
The dbglevel() method is used to set the debug level. Setting the dbglevel to 0 turns off debugging output and is suitable for production use. Setting the dbglevel to 1 or higher turns on increasingly verbose debug output.
* Signature: $context->dbglevel($dbglevel);
* Signature: $dbglevel = $context->dbglevel();
* Param: $dbglevel integer
* Return: $dbglevel integer
* Throws: App::Exception::Context
* Since: 0.01
Sample Usage:
$context->dbglevel(1); # turn it on
$context->dbglevel(0); # turn it off
$dbglevel = $context->dbglevel(); # get the debug level
debug_scope()
The debug_scope() method is used to get the hash which determines which debug statements are to be printed out when the debug level is set to a positive number. It returns a hash reference. If class names or "class.method" names are defined in the hash, it will cause the debug statements from those classes or methods to be printed.
* Signature: $debug_scope = $context->debug_scope();
* Param: void
* Return: $debug_scope {}
* Throws: App::Exception::Context
* Since: 0.01
Sample Usage:
$debug_scope = $context->debug_scope();
$debug_scope->{"App::Context::CGI"} = 1;
$debug_scope->{"App::Context::CGI.process_request"} = 1;
dump()
* Signature: $perl = $context->dump();
* Param: void
* Return: $perl text
* Throws: App::Exception
* Since: 0.01
Sample Usage:
print $self->dump(), "\n";
Protected Methods
These methods are considered protected because no class is ever supposed to call them. They may however be called by the context-specific drivers.
dispatch_events()
* Signature: $context->dispatch_events()
* Param: void
* Return: void
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$context->dispatch_events();
The dispatch_events() method is called by the bootstrap environmental code in order to get the Context object rolling. It causes the program to block (wait on I/O), loop, or poll, in order to find events from the environment and dispatch them to the appropriate places within the App-Context framework.
It is considered "protected" because no classes should be calling it.
send_results()
* Signature: $context->send_results()
* Param: void
* Return: void
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$context->send_results();
wait_for_event()
* Signature: $self->wait_for_event($event_token)
* Param: $event_token string
* Return: void
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$self->wait_for_event($event_token);
The wait_for_event() method is called when an asynchronous event has been sent and no more processing can be completed before it is done.
fork()
* Signature: $pid = $self->fork()
* Param: void
* Return: $pid integer
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$self->fork();
The fork() method is called in a child process just after it has been fork()ed. This causes connections to databases, etc. to be closed gracefully and new connections to be created if necessary.
Call this after a fork() in the child process. It will shut down the resources which cannot be shared between a parent and a child process.
Currently, this is primarily for database connections. For most databases, the child needs its own connection.
shutdown_unshareable_resources()
* Signature: $self->shutdown_unshareable_resources()
* Param: void
* Return: void
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$self->shutdown_unshareable_resources();
The shutdown_unshareable_resources() method is called in a child process just after it has been fork()ed. This causes connections to databases, etc. to be closed gracefully and new connections to be created if necessary.
Call this after a fork() in the child process. It will shutdown_unshareable which cannot be shared between a parent and a child process.
Currently, this is primarily for database connections. For most databases, the child needs its own connection.
shutdown()
The shutdown() method is called when the Context is preparing to exit. This allows for connections to databases, etc. to be closed gracefully.
* Signature: $self->shutdown()
* Param: void
* Return: void
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$self->shutdown();
response()
* Signature: $context->response()
* Param: void
* Return: void
* Throws: App::Exception
* Since: 0.01
Sample Usage:
$context->response();
The response() method gets the current Response being handled in the Context.