=head1 NAME

OpenInteract2::Manual::Architecture - Overview of the OpenInteract2 Architecture

=head1 SYNOPSIS

This part of the OpenInteract2 manual describes the major pieces of
the system and traces a users's request from catching the URL to
returning the content.

=head1 USING MVC LINGO

In case you've been hiding under a rock, MVC stands for
B<M>odel-B<V>iew-B<C>ontroller. It's a method of separating the
different concerns of your application for flexibility and other
reasons. While too broad to be a pattern it's still extremely useful
to keep in mind as you're developing.

MVC was developed in Smalltalk and targeted at desktop
applications. It's meant to decouple the various graphical widgets
from the actions resulting from them. While some (see link to Andy
Wardley's discussion in L<SEE ALSO>) have argued that MVC isn't
appropriate for web applications, it's still useful to categorize how
the different pieces of the application are separated.

=head2 Model

This is the smarts of your application and, unless you're a graphic
designer, probably the area on which you'll spend the most time. The
model consists of your application's core objects and processes. The
objects are normally persistent. So the model for a shopping cart
application may consist of the products in the cart (persistent), the
cart itself (semi-persistent), the customer (persistent), different
payment types (persistent) and the order process (transient).

Generally we use relational databases for persistence, but this also
encompasses other storage technologies (LDAP, GDBM, CSV, etc.).

In OpenInteract you most often use SPOPS to represent your
application's state as persistable objects. There are many hooks for
initializing SPOPS classes and adding useful behaviors to the
objects. But OI doesn't require that you use SPOPS for everything --
you can easily use another CPAN module (like L<Class::DBI|Class::DBI>)
for your model.

The processes are normally represented as Action objects, although
they may be generic enough to be a normal perl object that's
instantiated by an Action. To use the hackneyed shopping cart example:
the order process would probably be a separate object (e.g.,
'OpenInteract2::OrderProcess') so you can use it from a web action and
in response to emails or some other input

=head2 View

The view is what the user sees of your application. The view and model
communicate in a fairly limited but flexible fashion. In the GUI world
a typical MVC example would be a spreadsheet: one view is of tabular
data, another view is a pie chart, another view is a line chart. The
model stays the same, the view changes.

A typical web application view is a template with some sort of
processing engine behind it. The template takes some sort of data
structure and extracts the necessary information to display it to the
user.

OI is fairly flexible about views. The model (Action) always returns
content. Generally the Action will collect data, do some sort of
validation on it and then pass it on to the Content Generator along
with the name of a view. But the Action can also decide to return the
content itself. (This is unusual but has its place.)

The view name corresponds to a template file somewhere in a
package. So the view 'mypkg::foo' would refer to a file with a name
like C<$WEBSITE_DIR/pkg/mypkg-x.xx/template/foo>. And the Content
Generator is reponsible for taking the data from the model and passing
it to the view so it can be processed. The model doesn't care how the
data are used and the view doesn't care from where the data came.

=head2 Controller

Also known as a dispatcher, this is what decides which model (Action)
is called and how to represent the data from the outside world. These
are represented by the Controller object which dispatches the user's
request, the Request object which takes the user's inputs (however
they arrive) and translates them to a standard format, and the
Response object which translates the work done during the request
cycle into something the user can understand.

For a web application:

=over 4

=item *

The Request will store the URL requested, pull out useful information
from the headers and network information, and parse the GET/POST
request into parameters and file uploads.

=item *

The Controller instantiates the Action matching the URL as reported by
the Request, populates the Action with any necessary information and
executes the Action, capturing its output. It doesn't care what the
Action does or how the Action does it. The Controller will also place
this Action's output in a larger context (e.g., as part of a larger
web page) as necessary.

=item *

The Response returns the content along with any necessary headers to
the user.

=back

=head1 OI METADATA: CONTEXT

=head2 Overview

The Context (abbrev: CTX) glues the system together and is therefore
used everywhere. It holds all application configuration information
and provides a central lookup mechanism for actions, content
generators, controllers and SPOPS object classes. 

It is a singleton (there's only one in the system at any time) and
this singleton can be imported from the
L<OpenInteract2::Context|OpenInteract2::Context> class since it's used
fairly often.

=head2 Creating the Context

Creating the context is one of the first actions you take when
starting an OI2 server. While it can be created without referencing a
website it's not much use if you don't. (You should only need do this
when bootstrapping a new website into existence, and this is already
done for you in
L<OpenInteract2::Manage::Website::Create|OpenInteract2::Manage::Website::Create>.

So normally it looks something like this:

    my $ctx = OpenInteract2::Context->create(
                        { website_dir => $website_dir });


Once it's created the C<CTX> symbol can be imported and used anywhere,
like this:

    use OpenInteract2::Context qw( CTX );
    
    sub foo {
        my ( $self ) = @_;
        my $login_info = CTX->lookup_login_config;
        ...
    }

=head1 ADAPTER

=head2 Overview

The job of the adapter is to translate the world's information to
something understandable by OpenInteract and then translate what
OpenInteract generates into information for the outside world. So it
sits between your interface (e.g., Apache/mod_perl, CGI, etc.) and the
OpenInteract server. The information it translates from the outside
world includes parameters from the user, user authentication,
information about the request (hostname, URL, referer, cookies, etc.)
and other data. It places these data into the relevant
L<OpenInteract2::Request|OpenInteract2::Request> subclass.

Once the OpenInteract cycle is complete the adapter translates
OpenInteract data (content, headers, etc.) into a response to send
back to the user via the relevant
L<OpenInteract2::Response|OpenInteract2::Response> subclass. For an
example see L<Apache::OpenInteract2|Apache::OpenInteract2>.

=head2 Creating your own adapter

Creating an adapter is not difficult. Adapter classes tend to be
fairly short as most of the work is done in in the
L<OpenInteract2::Request|OpenInteract2::Request>/L<OpenInteract2::Response|OpenInteract2::Response>
subclasses. For instance, here's the full adapter for Apache/mod_perl
1.x:

   1: package Apache::OpenInteract2;
   2: 
   3: use strict;
   4: use Log::Log4perl            qw( get_logger );
   5: use OpenInteract2::Auth;
   6: use OpenInteract2::Constants qw( :log );
   7: use OpenInteract2::Context   qw( CTX );
   8: use OpenInteract2::Request;
   9: use OpenInteract2::Response;
  10: 
  11: sub handler($$) {
  12:     my ( $class, $r ) = @_;
  13:     my $log = get_logger( LOG_OI );
  14: 
  15:     $log->is_info &&
  16:         $log->info( scalar( localtime ), ": request from ",
  17:                     "[", $r->connection->remote_ip, "] for URL ",
  18:                     "[", $r->uri, '?', scalar( $r->args ), "]" );
  19: 
  20:     my $response = OpenInteract2::Response->new({ apache => $r });
  21:     my $request  = OpenInteract2::Request->new({ apache => $r });
  22: 
  23:     OpenInteract2::Auth->login( $r->pnotes( 'login_user' ) );
  24: 
  25:     my $controller = eval {
  26:         OpenInteract2::Controller->new( $request, $response )
  27:     };
  28:     if ( $@ ) {
  29:         $response->content( $@ );
  30:     }
  31:     else {
  32:         $controller->execute;
  33:     }
  34:     $response->send;
  35:     return $response->status;
  36: }
  37: 
  38: 1;

Very easy -- it's only about 15 lines if you remove the logging! This
even has a little twist by passing in the 'login_user' key from the
Apache C<pnotes> (line 23), which is a hook to the
L<Apache::OpenInteract2::HttpAuth|Apache::OpenInteract2::HttpAuth>
class to allow HTTP (rather than cookie) authentication.

Some gotchas to note:

=over 4

=item *

B<Tell OI2 what adapter you are>

Either at server startup or the first time your adapter processes a
request you must tell OI2 what type of adapter you are. This is very
simple, just two method calls on the L<OpenInteract2::Context>
object. Here's an example where we do it outside the adapter itself in
the Apache 1.x C<startup.pl> file:

 # Create the context...
 my $ctx = OpenInteract2::Context->create(
                 $base_config, { temp_lib_create => 'create' } );
 
 # ...let the context know what type of adapter we are
 $ctx->assign_request_type( 'apache' );
 $ctx->assign_response_type( 'apache' );

Here's one where we do it inside the adapter for a CGI process:

 my $ctx = OpenInteract2::Context->create(
                                { website_dir => $website_dir });
 $ctx->assign_request_type( 'cgi' );
 $ctx->assign_response_type( 'cgi' );

The currently available adapter types are:

=over 4

=item *

B<apache>: For Apache/mod_perl 1.x

=item *

B<apache2>: For Apache/mod_perl 2.x

=item *

B<cgi>: For CGI processes.

=item *

B<lwp>: For running inside a LWP server

=item *

B<standalone>: For setting everything up yourself, which means that it
could in theory run inside an SMTP daemon, FTP server, etc.

=back

You can add a new request/response type through the
C<register_factory_type> for both L<OpenInteract2::Request> and
L<OpenInteract2::Response>:

 # Register a 'fastcgi' request/response type
 OpenInteract2::Request->register_factory_type(
         fastcgi => 'OpenInteract2::Request::FastCGI' );
 OpenInteract2::Response->register_factory_type(
         fastcgi => 'OpenInteract2::Response::FastCGI' );

Now all calls to 'assign_request_type' and 'assign_response_type' will
have 'fastcgi' available.

=item *

B<Create response before request> - It may seem backwards but you need
to create the response object before the request object. (This is due
to a dependency.) 

=back

Additionally if your adapter is more of a standalone service (like the
C<oi2_daemon>) that spawns off children/threads for requests, you need
to also be aware of the following:

=over 4

=item * 

B<Initialize logging> - You'll need to initialize log4perl. This is
normally as simple as passing a parameter to the C<create> method of
L<OpenInteract2::Context|OpenInteract2::Context>, but you can also use
one of the methods in L<OpenInteract2::Log|OpenInteract2::Log>.

=item *

B<Close all database connections> - Before spawning off
children/threads from the parent you B<MUST> shutdown all database
connections. They won't survive the fork/thread and you'll get very
strange errors. Do this with the C<shutdown> method in
L<OpenInteract2::DatasourceManager|OpenInteract2::DatasourceManager>.

=back

=head1 CONTROLLER

=head2 Overview

Once the adapter has created the request and response it hands off the
processing to the
L<OpenInteract2::Controller|OpenInteract2::Controller> object. Now
we're entirely inside the OI2 server environment. This reads the
action and task from the request and creates the relevant action
object that will generate the content. It knows which action object to
create through a URL-to-action mapping created at Context startup. The
most-used controller
(L<OpenInteract2::Controller::MainTemplate|OpenInteract2::Controller::MainTemplate>)
places the generated content in a larger scope so you can control
common graphical elements (sidebars, menus, etc.) from once
place. Another controller
(L<OpenInteract2::Controller::Raw|OpenInteract2::Controller::Raw>)
returns the content as-is.

=head1 ACTION

=head2 Overview

Actions are the core of OpenInteract2. Each action provides a discrete
set of functionality. What "discrete set" means is up to the
developer, but typically this is a set of SCRUD (Search - CReate -
Update - Delete) operations on a class of objects.

Each action is represented by zero or more URLs, and each operation is
specified by a task referenced in that URL. So if I created a 'news'
action my URLs might look like:

Every task returns some sort of content, generally by passing data to
a Content Generator which marries it with a template. See
L<OpenInteract2::Action|OpenInteract2::Action> for much more
information.

=head1 CONTENT GENERATOR

=head2 Overview

As mentioned above tasks in an Action return content. They normally
generate that content by assembling a set of data and passing that
data off to a content generator. A content generator is a wrapper
around some sort of templating system, such as the L<Template|Template
Toolkit>, L<HTML::Template|HTML::Template> or
L<Text::Template|Text::Template> or even your own homegrown
system. (Admit it, you've written your own.)

Each action is associated with a content generator. And you can even
associate an action with multiple content generators so you can settle
a bet as to which templating system is easiest to use.

=head1 TRACING A REQUEST

Now we'll trace a request throughout OpenInteract.

=head2 Step 0: Startup Tasks

The adapter or another process (e.g., 'startup.pl' in a mod_perl
setup) will run a number of tasks at server startup. This includes:

=over 4

=item *

Initialize logging

=item *

Create context with website directory

=item *

Assign the proper request/response types to request

=item *

If threaded/forking: disconnect all database handles.

=back

=head2 Step 1: User Request Meets Adapter

This step is a little fuzzy by necessity: we purposefully don't know
in what form the request is coming in or how the adapter handles it.

=head2 Step 2: Adapter Creates Request/Response Objects

The adapter creates the
L<OpenInteract2::Response|OpenInteract2::Response> and
L<OpenInteract2::Request|OpenInteract2::Request> objects, in that
order. Each one has necessary initialization steps done behind the
scenes when you create it. In particular the request object will read
the necessary headers, parameters, uploaded files, cookies and create
the session from the cookie.

It also finds the 'relevant' part of the URL and determines the action
and task from it. The 'relevant' part is what's leftover after the
URL-space (aka, deployment context, set in the
C<context_info.deployed_under> server configuration key) is lopped off.

=head2 Step 3: Adapter Logs in User

It can optionally handle extra authentication as this point such as
HTTP auth or some other capability. Generally this will consist of
retrieving a user object created from some other part of the system or
creating a user object based on trusted information (like a user ID)
from another area.

If available this user object is passed to the C<login> method of the
L<OpenInteract2::Auth|OpenInteract2::Auth> class so it has a head
start.

=head2 Step 4: Adapter Creates Controller

Adapter creates the
L<OpenInteract2::Controller|OpenInteract2::Controller> object with the
request and response objects created earlier.

The controller asks the request for the action name and asks the
context for an action object of that name. (It's always a subclass of
L<OpenInteract2::Action|OpenInteract2::Action>.) If the action name
exists but is not found we use the action named in the
C<action_info.not_found> server configuration key. If the action name
doesn't exist we use the action from C<action_info.none>.

Once the action is found we assign it the task (if available) as
reported by the request.

=head2 Step 5: Adapter Executes Controller

If created properly the adapter calls C<execute()> on the
controller. This starts the content generation process running. 

The controller will call C<execute()> on the action which returns the
content for it.

=head2 Step 6: Action Finds Task 

The action needs to find which task to execute. Normally this is as
simple as getting the value of the C<task> property. But the
individual action can override this, or if no task was specified we
use the value of C<task_default>.

=head2 Step 7: Action Checks Validity

Find out if the task is invalid. A valid task:

=over 4

=item *

Does not start with a '_'

=item *

Is not listed in C<task_invalid>

=item *

Is listed among the tasks in in C<task_valid> if that property is
defined.

=back

If the task is valid we also ensure that this user has the proper
security level to execute it.

=head2 Step 8: Action Generates Content

First, we check the cache to see if content exists and if it does, we
return it without going any further.

Next we execute the method specified by what we've determined to be
the task. (This is almost certainly the method with the same name as
the task.)

An action can generate content by itself but most times it just
gathers the necessary data and passes it, along with a template
specification, to a content generator which returns the content for
the action.

If the cache is activated for this method we'll cache the content. In
any case we return the content, finishing the flow for the action and
moving back up to the controller.

=head2 Step 9: Controller Places Action Content in Larger Scope (optional)

The main action is done and has returned its content to the
controller. One controller
(L<OpenInteract2::Controller::Raw|OpenInteract2::Controller::Raw>)
will just return this content and call it a day.

Most times you'll want to take that content and put it into another
template. The controller just instantiates a new content generator and
goes through the same process as the action, passing it a set of data
(of which the generated action content is part) and a template
specification (normally from the 'main_template' theme property).

Oftentimes the main template will hold multiple discrete actions of
its own. For example, the default main template shipped with OI has an
action to generate the list of boxes that appears on the right-hand
side. You could trigger an action to get the latest weather
conditions, webcam photo, news headlines, whatever you wish.

Each of these actions is just like any other and goes through the same
process listed above.

=head2 Step 10: Controller Sets Content to Response

Whether it's the action content or the scoped content (for lack of a
better name), we set the content in the response object, which hasn't
done much until now except hold the occasional outgoing cookie.

The controller's job is done and flow now returns back up a level to
the adapter.

=head2 Step 11: Adapter Asks Response to Send

The only job left of the adapter is to ask the response to send the
content.

=head2 Step 12: Adapter Cleans Up

The adapter can do any necessary cleanup.

=head1 SEE ALSO

Andy Wardley's email about MVC and web applications:

L<http://lists.ourshack.com/pipermail/templates/2002-November/003974.html>

=head1 COPYRIGHT

Copyright (c) 2002-2004 Chris Winters. All rights reserved.

=head1 AUTHORS

Chris Winters E<lt>chris@cwinters.comE<gt>
