%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright 2001 by Object Craft P/L, Melbourne, Australia.
% LICENCE - see LICENCE file distributed with this software for details.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\chapter{Guide to Building Applications\label{app-guide}}

Roughly speaking, every page or document sent from a web server to a
browser is the result of the same processing sequence.  For our
purposes a document is one page in an application.

\begin{enumerate}
\item
The browser connects to the server and requests a page.

\item
The server decodes the browser request and processes it.  This can
cause all manner of subsidiary application processing to occur.

\item
The server sends the result of processing back to the browser as the
next page in the application.
\end{enumerate}

The essentially stateless nature of the web presents problems for the
application developer who wishes to retain state between different
pages in their application.  From the point of view of the user, the
state of the application at the server is represented by the page that
they see in their browser window(s).  When they enter values and press
submit buttons on their page they (quite reasonably) expect the
application on the web server to process their request and return the
next page in the application.

The point of view of the web application developer is very different.
At the server side the application must be able to receive a request
from one browser, process it and send the next application page back
to that browser.  Before seeing the next request from the same
browser, another browser may request a different page from the
application.  The web application even has to deal with multiple
browsers simultaneously accessing different pages in the application.
All of this while maintaining the illusion for the end user that they
are running their own copy of the application.

Even when you only have a single machine running Apache, there are
multiple Apache processes on that machine that are receiving and
processing browser requests.  This means that there is no guarantee
that the same process that received the last request from a
particular browser will receive the next request from that browser.
If your application requires some state to be retained between pages,
there has to be a way for that state to migrate between different
Apache processes.  If you are using more than one machine to process
requests, then you need some way for the application state to move
between machines.

There are essentially three approaches to solving the state
propagation problem.

\begin{enumerate}
\item
Deploy a stateless application.  Only the most trivial applications do
not require state to be retained across browser requests.

\item
Get the browser to store the application state.  This can be done by
embedding information in URL's and hidden fields in forms.  When the
browser requests the next page the application restores state by
extracting it from the hidden field values sent back by the browser.
Browser cookies can also be used to store some types of application
state.

\item
Get the browser to store a session identifier in either URL's, hidden
fields, or a cookie.  When the browser requests the next page the
application uses the browser supplied session identifier to locate the
state in a server-side session database of some description.
\end{enumerate}

Assuming that your application is non-trivial, the second approach
(state held by the browser) is the easiest to implement.

If you are building a financial application, you will probably feel
more comfortable with the third approach.  This has the advantage of
hiding implementation details of your application from prying eyes.

All three approaches are supported (in one way or another) by
Albatross.

In all Albatross applications there are two important objects that
determine how browser requests are processed; the application object,
and the execution context object.  The application is a potentially
long lived object that provides generic services for multiple browser
requests.  A new execution context is created to process each browser
request.

One of the things that the application and execution context do is
cooperate to provide session functionality.  The execution context is
the object where session data is created and manipulated, but the
application is usually responsible to loading and saving the session.
This allows the application to maintain a long lived connection with a
server if necessary.

\section{Albatross Application Model\label{app-model}}

In the Albatross world view explained in the previous section, all web
applications follow the same processing sequence to handle browser
requests.  When processing a browser request to generate a response
the processing (in most cases) flows according to figure
\ref{fig-dataflow}.

\begin{figure}[h]
\begin{center}
\includegraphics{dataflow}
\caption{Request Processing Dataflow\label{fig-dataflow}}
\end{center}
\end{figure}

The processing steps are:

\begin{enumerate}
\item
Capture the browser request in a \class{Request} object.

\item
Pass the \class{Request} object to the \method{run()} method of the
application object.

\item
Application locates the Python code for processing the browser
request.

\item
Page processing code runs one or more Albatross templates.

\item
Templates contain either standard Albatross tags or application
defined extension tags.

\item
As tags are converted to HTML a stream of content fragments is sent to
the execution context.

\item
When the execution context content is flushed all of the fragments are
joined together.

\item
Joined flushed content is sent to the \class{Request} object
\method{write_content()} method.

\item
Application response is returned to the browser.
\end{enumerate}

In the Albatross code the processing is driven by the \method{run()}
method of the \class{Application} class in the \module{app} module.

It is instructive to look at the \emph{exact} code from Albatross that
implements the processing sequence.

\label{app-proc-seq}
\begin{verbatim}
    ctx = self.create_context()
    ctx.set_request(req)
    self.load_session(ctx)
    self.load_page(ctx)
    if self.validate_request(ctx):
        self.merge_request(ctx)
        self.process_request(ctx)
    self.display_response(ctx)
    self.save_session(ctx)
    ctx.flush_content()
\end{verbatim}

The code is contained within a \code{try}/\code{except} block to allow
the application to trap and handle exceptions.

The \class{Application} class assumes very little about the
implementation of each of these steps.  The detail of the processing
stages is defined by a collection of mixin classes.  A combination of
the \class{Application} class and a selection of the mixin classes is
used to construct your application class and execution context
classes.  There are a number of prefabricated applications and
execution contexts, see chapter \ref{pack-overview}.

This mix and match approach to building the application and execution
context classes provides a great deal of flexibility.  Albatross is an
application toolkit, not a deployment platform.  You are encouraged to
look at the code and develop your own mixin classes to suit your
deployment requirements.  One of the primary goals of Albatross is to
keep the toolkit line count low.  This reduces the amount of time you
need to spend before you can make your own custom extensions to the
toolkit.

In the previous chapter we talked about the importance of separating
the presentation layer of the application from the implementation as
shown in figure \ref{fig-presimp}.  Albatross HTML templates provide a
fairly powerful tool for achieving that separation.

\begin{figure}[h]
\begin{center}
\includegraphics{twolayer}
\caption{Separation of Presentation/Implementation\label{fig-presimp}}
\end{center}
\end{figure}

The presentation layer consists of a collection of template files
that contain the logic required to display data from the objects
contained in the implementation layer.  In Albatross, the line between
the two layers is the execution context.

To make objects available to the presentation layer the application
places references to those objects into the local or global namespace
of the execution context.  The local namespace is populated in
application code like this:

\begin{verbatim}
    ctx.locals.mbox = Mbox(ctx.locals.username, ctx.locals.passwd)
    ctx.locals.msg = ctx.locals.mbox[int(ctx.locals.msgnum) - 1]
\end{verbatim}

To execute Python expressions inside the template files, the execution
context uses the following Python code from the \class{NamespaceMixin}
class:

\begin{verbatim}
    def eval_expr(self, expr):
        self.locals.__ctx__ = self
        try:
            return eval(expr, self.__globals, self.locals.__dict__)
        finally:
            del self.locals.__ctx__
\end{verbatim}

Whenever application code calls the \method{run_template()} or
\method{run_template_once()} methods of the \class{NamespaceMixin}
class Albatross sets the global namespace (via
\method{set_globals()}) for expression evaluation (in
\member{self.__globals}) to the globals of the function that called
\method{run_template()} or \method{run_template_once()}.

Not many applications are output only, most accept browser input.  The
Albatross application object merges the browser request into the
execution context in the \method{merge_request()} method.  Referring
back to the application processing sequence also note that the
application object displays the result of processing the browser
request via the execution context.

With this in mind figure \ref{fig-presimp} becomes figure
\ref{fig-presimpexec}.

\begin{figure}[h]
\begin{center}
\includegraphics{twolayerctx}
\caption{Presentation/Implementation and Execution Context\label{fig-presimpexec}}
\end{center}
\end{figure}

The only thing missing is the application glue that processes the
browser requests, places application objects into the execution
context, and directs the execution of template files.

The application model built into Albatross is intended to facilitate
the use of a model-view-controller like approach (see figure
\ref{fig-mvc}) to constructing your application.  There are many
excellent descriptions of the model-view-controller design pattern
which can be found by searching for ``model view controller'' on
\url{http://www.google.com/}.

\begin{figure}[h]
\begin{center}
\includegraphics{mvc}
\caption{Albatross model-view-controller\label{fig-mvc}}
\end{center}
\end{figure}

The \emph{user} invokes application functions via the
\emph{controller} through the \emph{view}.  The \emph{controller}
contains logic to direct the application functionality contained
within the \emph{model}.  All of the real application functionality is
in the \emph{model}, not the \emph{controller}.  Changes to the
application \emph{model} are then propagated to the \emph{view} via
the \emph{controller}.

In Albatross terms, the implementation layer is the \emph{model} and
the presentation layer is the \emph{view}.  The application glue
plays the role of the \emph{controller}.  By divorcing all application
logic from the \emph{view} and \emph{controller} you are able to
construct unit test suites for your application functionality using
the Python \module{unittest} module.

Albatross uses an approach inspired by the traditional
model-view-controller design pattern.  So now we can draw the final
version of the diagram which shows how Albatross applications process
browser requests in figure \ref{fig-appmodel}.

\begin{figure}[h]
\begin{center}
\includegraphics{albmvc}
\caption{Albatross Application Model\label{fig-appmodel}}
\end{center}
\end{figure}

As you can see the execution context is central to all of the
Albatross processing.  It is worth revisiting the application
processing sequence set out on page \pageref{app-proc-seq} at the
start of this section to see how the application draws all of the
elements together.

During step four (page processing) the Albatross application object
will call on your application code to process the browser request.

There are a number of different ways in that your application code can
be ``attached'' to the Albatross application object.  The
\class{PageObjectMixin} application mixin class requires that you
implement application functionality in ``page objects'' and define
methods that can be called by the toolkit.  As an example, here is
the page object for the \texttt{'login'} page of the \texttt{popview}
sample application.

\begin{verbatim}
class LoginPage:

    name = 'login'

    def page_process(self, ctx):
        if ctx.req_equals('login'):
            if ctx.locals.username and ctx.locals.passwd:
                try:
                    ctx.open_mbox()
                    ctx.add_session_vars('username', 'passwd')
                except poplib.error_proto:
                    return
                ctx.set_page('list')

    def page_display(self, ctx):
        ctx.run_template('login.html')
\end{verbatim}

When the toolkit needs to process the browser request it calls the
\method{page_process()} method of the current page object.  As you can
see, the code determines which request was made by the browser,
instantiates the application objects required to service the
browser request, then directs the context to move to a new page via
the \method{set_page()} method.

When Albatross is ready to display the browser response it calls the
\method{page_display()} method of the current page object.  In the
code above, \method{set_page()} is only called if the mailbox is
opened successfully.  This means that a failed login will result in
the login page being displayed again.

Note that when you change pages the object that generates the HTML
will be a different object to that that processed the browser
request.

To let you get a foothold on the toolkit application functionality we
will work through another variant of the \texttt{form} application.

\section{Using Albatross Input Tags (Again)\label{tug-form4}}

In the previous chapter we demonstrated the use of Albatross input
tags to transfer values from the execution context into HTML
\texttt{<input>} tags, and from the browser request back into the
execution context.  In this section we present the same process using
an Albatross application object.

The sample program from this section is supplied in the
\texttt{samples/form4} directory and can be installed in your web
server \texttt{cgi-bin} directory by running the following commands.

\begin{verbatim}
cd samples/form4
python install.py
\end{verbatim}

The \texttt{form.html} template file used by the application follows.

\verbatiminput{../samples/form4/form.html}

The most important new features in the template file are the use of
the \texttt{<al-form>} tag, and the \texttt{list} attribute in the
\texttt{<al-input~type="checkbox">} tag.

Most execution contexts created by application objects inherit from
the \class{NameRecorderMixin}.  The \class{NameRecorderMixin} records
the name, type and multiple value disposition of each input tag in a
form in a hidden field named \texttt{__albform__}.  The recording
process requires that all \texttt{<al-input>} tags be enclosed by an
\texttt{<al-form>} tag.

Any input field with the \texttt{list} attribute will always receive a
list value from a POST browser request regardless of how many values
(including none) were sent by the browser.  An exception will be
raised if you specify multiple input tags with the same name in a form
and do not include the \texttt{list} attribute.  The input tag types
\texttt{radio}, \texttt{image}, and \texttt{submit} are implicitly
flagged to receive multiple values so the \texttt{list} attribute must
not be specified on these.

The \texttt{form.py} program is show below.

\verbatiminput{../samples/form4/form.py}

You can run the program by pointing your browser at
\mbox{\url{\cgibindir/alsamp/form4/form.py}}.

Notice that the browser request is automatically merged into the local
namespace and then extracted by the template when generating the HTML
response.

The program uses the \class{SimpleApp} application class.
\class{SimpleApp} uses an object to define each page served by the
application.  Each of the page objects must be registered with the
application via the \method{register_page()} method.

When the application enters a new page \class{SimpleApp} calls the
\method{page_enter()} method of the page object to allow the
application to initialise execution context values.  In the above
program the \method{page_enter()} method initialises all values used
by the HTML form to \code{None}, initialises the variable \var{num} to
\code{0} and places it into the session.

As shown in the application processing sequence on page
\pageref{app-proc-seq}, the first step in handling a browser request
is to create an execution context.  The \class{SimpleApp} class uses
instances of the \class{SimpleAppContext} class which inherits from
\class{HiddenFieldSessionMixin}.  The \class{HiddenFieldSessionMixin}
class stores session data in a hidden field named
\texttt{__albstate__} at the end of each form.

When an Albatross application needs to display the result of
processing a request it calls the \method{page_display()} method of
the current page.  In the above program this method increments
\var{num} and then runs the \texttt{form.html} template.  It is
important to note that any changes to session values after executing a
template will be lost as the session state is saved in the HTML
produced by the template.

It is worth explaining again that the program does not perform any
request merging --- this is all done automatically by the Albatross
application and execution context objects.

\section{The Popview Application\label{app-popview1}}

In this section we will develop a simple application that allows a
user to log onto a POP server to view the contents of their mailbox.
Python provides the \module{poplib} module which provides a nice
interface to the POP3 protocol.

The complete sample program is contained in the
\texttt{samples/popview1} directory.  Use the \texttt{install.py}
script to install the sample.

\begin{verbatim}
cd samples/popview1
python install.py
\end{verbatim}

First of all let's create the \emph{model} components of the
application.  This consists of some classes to simplify access to a
user mailbox.  Create a module called \texttt{popviewlib.py} and start
with the \class{Mbox} class.

\begin{verbatim}
import string
import poplib

pophost = 'pop'


class Mbox:

    def __init__(self, name, passwd):
        self.mbox = poplib.POP3(pophost)
        self.mbox.user(name)
        self.mbox.pass_(passwd)

    def __getitem__(self, i):
        try:
            return Msg(self.mbox, i + 1)
        except poplib.error_proto:
            raise IndexError
\end{verbatim}

The important feature of our \class{Mbox} class is that it implements
the Python sequence protocol to retrieve messages.  This allows us to
iterate over the mailbox using the \texttt{<al-for>} tag in templates.
When there is an attempt to retrieve a message number which does not
exist in the mailbox, a \module{poplib.error_proto} exception will be
raised.  We transform this exception into an \exception{IndexError}
exception to signal the end of the sequence.

The sequence protocol is just one of the truly excellent Python
features which allows your application objects to become first class
citizens.

Next we need to implement a \class{Msg} class to access the header and
body of each message.

\begin{verbatim}
class Msg:

    def __init__(self, mbox, msgnum):
        self.mbox = mbox
        self.msgnum = msgnum
        self.read_headers()

    def read_headers(self):
        res = self.mbox.top(self.msgnum, 0)
        hdrs = Headers()
        hdr = None
        for line in res[1]:
            if line and line[0] in string.whitespace:
                hdr = hdr + '\n' + line
            else:
                hdrs.append(hdr)
                hdr = line
        hdrs.append(hdr)
        self.hdrs = hdrs
        return hdrs

    def read_body(self):
        res = self.mbox.retr(self.msgnum)
        lines = res[1]
        for i in range(len(lines)):
            if not lines[i]:
                break
        self.body = string.join(lines[i:], '\n')
        return self.body
\end{verbatim}

Note that we retrieve the message headers in the constructor to ensure
that the creation of the \class{Msg} object will fail if there is no
such message in the mailbox.  The \class{Mbox} class uses the
exception raised by the \module{poplib} module to detect when a
non-existent message is referenced.

The \module{poplib} module returns the message headers as a flat list
of text lines.  It is up to the \module{poplib} user to process those
lines and impose a higher level structure upon them.  The
\method{read_headers()} method attaches header continuation lines to
the corresponding header line before passing each complete header to a
\class{Headers} object.

The \method{read_body()} method retrieves the message body lines from
the POP server and combines them into a single string.

We are going to need to display message headers by name so our
\class{Headers} class implements the dictionary protocol.

\begin{verbatim}
class Headers:

    def __init__(self):
        self.hdrs = {}

    def append(self, header):
        if not header:
            return
        parts = string.split(header, ': ', 1)
        name = string.capitalize(parts[0])
        if len(parts) > 1:
            value = parts[1]
        else:
            value = ''
        curr = self.hdrs.get(name)
        if not curr:
            self.hdrs[name] = value
            return
        if type(curr) is type(''):
            curr = self.hdrs[name] = [curr]
        curr.append(value)

    def __getitem__(self, name):
        return self.hdrs.get(string.capitalize(name), '')
\end{verbatim}

Instead of raising a \exception{KeyError} for undefined headers, the
\method{__getitem__()} method returns the empty string.  This allows us to
test the presence of headers in template files without being exposed
to exception handling.

Lets take all of these classes for a spin in the Python
interpreter.

\begin{verbatim}
>>> import popviewlib
>>> mbox = popviewlib.Mbox('djc', '***')
>>> msg = mbox[0]
>>> msg.hdrs['From']
'Owen Taylor <otaylor@redhat.com>'
>>> print msg.read_body()

Daniel Egger <egger@suse.de> writes:

> Am 05 Aug 2001 12:00:15 -0400 schrieb Alex Larsson:
> 
[snip]
\end{verbatim}

Next we will create the application components (the \emph{controller})
in \texttt{popview.py}.  Albatross has a prepackaged application
object which you can use for small applications; the \class{SimpleApp}
class.

In anything but the most trivial applications it is probably a good
idea to draw a site map like figure \ref{fig-popview-sitemap} to help
visualise the application.

Our application will contain three pages; login, message list, and
message detail.

\begin{figure}[h]
\begin{center}
\includegraphics{pagemap}
\caption{Popview Site Map\label{fig-popview-sitemap}}
\end{center}
\end{figure}

The \class{SimpleApp} class inherits from the \class{PageObjectMixin}
class which requires that the application define an object for each
page in the application.

Albatross stores the current application page identifier in the local
namespace of the execution context as \member{__page__}.  The value is
automatically created and placed into the session.

When the current page changes, the Albatross application object calls
the \method{page_enter()} function/method of the new page object.  The
\method{page_process()} method is called to process a browser request,
and finally \method{page_display()} is called to generate the
application response.

The \class{SimpleApp} class creates \class{SimpleAppContext} execution
context objects.  By subclassing \class{SimpleApp} and overriding
\method{create_context()} we can define our own execution context
class.

The prologue of the application imports the required application and
execution context classes from Albatross and the \class{Request} class
from the deployment module.

\begin{verbatim}
#!/usr/bin/python
from albatross import SimpleApp, SimpleAppContext
from albatross.cgiapp import Request
import poplib
import popviewlib
\end{verbatim}

Next in the file is the class for the login page.  Note that we only
implement glue (or \emph{controller}) logic in the page objects.  Each
time a new page is served we will need to open the mail box and
retrieve the relevant data.  That means that the username and password
will need to be stored in some type of session data storage.

\begin{verbatim}
class LoginPage:

    name = 'login'

    def page_process(self, ctx):
        if ctx.req_equals('login'):
            if ctx.locals.username and ctx.locals.passwd:
                try:
                    ctx.open_mbox()
                    ctx.add_session_vars('username', 'passwd')
                except poplib.error_proto:
                    return
                ctx.set_page('list')

    def page_display(self, ctx):
        ctx.run_template('login.html')
\end{verbatim}

The \method{req_equals()} method of the execution context looks inside
the browser request for a field with the specified name.  It returns a
TRUE value if such a field exists and it has a value not equal to
\code{None}.  The test above will detect when a user presses the
submit button named \texttt{'login'} on the \texttt{login.html} page.

Next, here is the page object for displaying the list of messages in
the mailbox.  You will notice one small wart in the request
processing; since the \texttt{'detail'} request is implemented in an
\texttt{<input type="image">} tag, the browser sends \texttt{x} and
\texttt{y} coordinates where the mouse was clicked in the image.

\begin{verbatim}
class ListPage:

    name = 'list'

    def page_process(self, ctx):
        if ctx.req_equals('detail.x'):
            ctx.set_page('detail')

    def page_display(self, ctx):
        ctx.open_mbox()
        ctx.run_template('list.html')
\end{verbatim}

The ``detail'' page displays the message detail.

\begin{verbatim}
class DetailPage:

    name = 'detail'

    def page_process(self, ctx):
        if ctx.req_equals('list'):
            ctx.set_page('list')

    def page_display(self, ctx):
        ctx.open_mbox()
        ctx.read_msg()
        ctx.run_template('detail.html')
\end{verbatim}

And finally we define the application class and instantiate the
application object.  Note that we have subclassed \class{SimpleApp} to
create our own application class.  This allows us to implement our own
application level functionality as required.

\begin{verbatim}
class AppContext(SimpleAppContext):

    def open_mbox(self):
        if hasattr(self.locals, 'mbox'):
            return
        self.locals.mbox = popviewlib.Mbox(self.locals.username, self.locals.passwd)

    def read_msg(self):
        if hasattr(self.locals, 'msg'):
            return
        self.locals.msg = self.locals.mbox[int(self.locals.msgnum) - 1]
        self.locals.msg.read_body()


class App(SimpleApp):

    def __init__(self):
        SimpleApp.__init__(self,
                           base_url='popview.py',
                           template_path='.',
                           start_page='login',
                           secret='-=-secret-=-')
        for page_class in (LoginPage, ListPage, DetailPage):
            self.register_page(page_class.name, page_class())

    def create_context(self):
        return AppContext(self)


app = App()


if __name__ == '__main__':
    app.run(Request())
\end{verbatim}

The \var{base_url} argument to the application object constructor will
be placed into the \texttt{action} attribute of all forms produced by
the \texttt{<al-form>} tag.  It will also form the left hand side of
all hrefs produced by the \texttt{<al-a>} tag.  The
\var{template_path} argument is a relative path to the directory that
contains the application template files.  The \var{start_page}
argument is the name of the application start page.  When a browser
starts a new session with the application it will be served the
application start page.

We have also created our own execution context to provide some
application functionality as execution context methods.

With the \emph{model} and \emph{controller} components in place we can
now move onto the template files that comprise the \emph{view}
components of the application.

First let's look at the \texttt{login.html} page.

\verbatiminput{../samples/popview1/login.html}

When you look at the HTML produced by the application you will notice
two extra \texttt{<input>} tags have been generated at the bottom of
the form.  They are displayed below (reformatted to fit on the page).

\label{alb-hidden}
\begin{verbatim}
<input type="hidden" name="__albform__" value="eJzTDJeu3P90rZC6dde04xUhHL
WFjBqhHKXFqUV5ibmphUzeDKFsBYnFxeUphcxANmtOfnpmXiGLN0OpHgB7UBOp
">
<input type="hidden" name="__albstate__" value="eJzT2sr5Jezh942TUrMty6q1j
WsLGUM54uMLEtNT4+MLmUJZc/LTM/MKmYv1AH8XEAY=
">
\end{verbatim}

If we fire up the Python interpreter we can have a look at what these
fields contain.

\begin{verbatim}
>>> import base64,zlib,cPickle
>>> s = "eJzTDJeu3P90rZC6dde04xUhHL\n" + \
... "WFjBqhHKXFqUV5ibmphUzeDKFsBYnFxeUphcxANmtOfnpmXiGLN0OpHgB7UBOp\n"
>>> cPickle.loads(zlib.decompress(base64.decodestring(s))[16:])
{'username': 0, 'passwd': 0, 'login': 0}
>>> s = "eJzT2sr5Jezh942TUrMty6q1j\n" + \
... "WsLGUM54uMLEtNT4+MLmUJZc/LTM/MKmYv1AH8XEAY=\n"
>>> cPickle.loads(zlib.decompress(base64.decodestring(s))[16:])
{'__page__': 'login'}
\end{verbatim}

The first string contains a dictionary that defines the name and type
of the input fields that were present in the form.  This is placed
into the form by the \class{NameRecorderMixin} class which is
subclassed by \class{SimpleAppContext}.  If you look at the definition
of \class{SimpleAppContext} you will notice the following definition
at the start of the class.

\begin{verbatim}
NORMAL, LIST, FILE = range(3)
\end{verbatim}

The value \code{0} for each field in the dictionary above corresponds
to field type \code{NORMAL}.

When merging the browser request into the execution context the
dictionary of field names is used to assign the value \code{None} to
any \code{NORMAL} or \code{FILE} fields, or \code{[]} to any
\code{LIST} fields that were left empty by the user.  This is useful
because it lets us write application code which can ignore the fact
that fields left empty by the user will not be sent by the browser
when the form is submitted.

The second string contains all of the session values for the
application.  In the application start page the only session variable
that exists is the \member{__page__} variable.  The
\class{HiddenFieldSessionMixin} places this field in the form when the
template is executed and pulls the field value back out of the browser
request into the execution context when the session is loaded.

The first 16 bytes of the decompressed string is an MD5 sign.  This
was generated by MD5 signing the application secret (passed as the
\var{secret} argument to the application object) prepended to the
pickle string.  When the field is sent back to the application the
signing process is repeated.  The pickle is only loaded if the sign
sent by the browser and the regenerated sign are the same.

Since the \texttt{popview} application has been provided for example
purposes you will probably forgive the usage of the
\class{HiddenFieldSessionMixin} class to propagate session state.  In
a real application that placed usernames and passwords in the session
you would probably do something to protect these values from prying
eyes.

Now let's look at the \texttt{list.html} template file.

Note that the use of the \texttt{<al-flush>} tag causes the HTML
output to be streamed to the browser.  Use of this tag can give your
application a much more responsive feel when generating pages that
involve lengthy processing.

A slightly obscure feature of the page is the use of a separate form
surrounding the \texttt{<al-input~type="image">} field used to select
each message.  An unfortunate limitation of the HTML
\texttt{<input~type="image">} tag is that you cannot associate a value
with the field because the browser returns the coordinates where the
user pressed the mouse inside the image.  In order to associate the
message number with the image button we place the message number in a
separate hidden \texttt{<input>} field and group the two fields using
a form.

You have to be careful creating a large number of forms on the page
because each of these forms will also contain the \texttt{__albform__}
and \texttt{__albstate__} hidden fields.  If you have a lot of data in
your session the size of the \texttt{__albstate__} field will cause
the size of the generated HTML to explode.

\verbatiminput{../samples/popview1/list.html}

Finally, here is the message detail page \texttt{detail.html}.

\verbatiminput{../samples/popview1/detail.html}

\section{Adding Pagination Support to Popview\label{app-popview2}}

If the previous section we constructed a simple application for
viewing the contents of a mailbox via the \module{poplib} module.  One
problem with the application is that there is no limit to the number
of messages that will be displayed.  In this section we will build
pagination support into the message list page.

We will modify the application to display 15 messages on each page and
will add buttons to navigate to the next and previous pages.  The
\texttt{pagesize} attribute of the \texttt{<al-for>} tag provides
automatic pagination support for displaying sequences.  The only extra
code that we need to add is a \texttt{__len__} method to the
\class{Mbox} class which returns the number of messages in the
mailbox.  This \texttt{__len__} method is needed to allow the template
file to test whether or not to display a next page control.

The complete sample program is contained in the
\texttt{samples/popview2} directory.  Use the \texttt{install.py}
script to install the sample.

\begin{verbatim}
cd samples/popview2
python install.py
\end{verbatim}

Add a \texttt{__len__} method to the \class{Mbox} class in
\texttt{popviewlib.py}.

\begin{verbatim}
class Mbox:

    def __init__(self, name, passwd):
        self.mbox = poplib.POP3(pophost)
        self.mbox.user(name)
        self.mbox.pass_(passwd)

    def __getitem__(self, i):
        try:
            return Msg(self.mbox, i + 1)
        except poplib.error_proto:
            raise IndexError

    def __len__(self):
        len, size = self.mbox.stat()
        return len
\end{verbatim}

Now we modify the template file \texttt{list.html}.

\verbatiminput{../samples/popview2/list.html}

The \texttt{<al-for>} tag just below the \texttt{<body>} tag contains
two new attributes; \texttt{pagesize} and \texttt{prepare}.

The \texttt{pagesize} turns on pagination for the \texttt{<al-for>}
\class{ListIterator} object and defines the size of each page.  In
order to remember the current top of page between pages, the tag
places the iterator into the session.  When saving the iterator, only
the top of page and pagesize are retained.

The \texttt{prepare} attribute instructs the \texttt{<al-for>} tag to
perform all tasks except actually display the content of the sequence.
This allows us to place pagination controls before the actual display
of the list.

\section{Adding Server-Side Session Support to Popview\label{app-popview3}}

So far we have been saving all application state at the browser inside
hidden fields.  Sometimes it is preferable to retain state at the
server side.  Albatross includes support for server-side sessions in
the \class{SessionServerContextMixin} and
\class{SessionServerAppMixin} classes.  In this section we will modify
the \texttt{popview.py} program to use server-side sessions.

The \class{SessionServerAppMixin} class uses a socket to communicate
with the \texttt{session-server/al-session-daemon} session server.
You will need to start this program before using the new
\code{popview} application.

In previous versions of the program we were careful to place all user
response into forms.  This allowed Albatross to transparently attach
the session state to hidden fields inside the form.  When using
server-side sessions Albatross does not need to save any application
state at the browser so we are free to use URL style user inputs.  To
illustrate the point, we will replace all of the form inputs with URL
user inputs.

The complete sample program is contained in the
\texttt{samples/popview3} directory.  Use the \texttt{install.py}
script to install the sample.

\begin{verbatim}
cd samples/popview3
python install.py
\end{verbatim}

The new \texttt{list.html} template file follows.

\verbatiminput{../samples/popview3/list.html}

Next the new \texttt{detail.html} template file.

\verbatiminput{../samples/popview3/detail.html}

One of the more difficult tasks for developing stateful web
applications is dealing with browser requests submitted from old pages
in the browser history.

When all application state is stored in hidden fields in the HTML,
requests from old pages do not usually cause problems.  This is
because the old application state is provided in the same request.

When application state is maintained at the server, requests from old
pages can cause all sorts of problems.  The current application state
at the server represents the result of a sequence of browser requests.
If the user submits a request from an old page in the browser history
then the fields and values in the request will probably not be
relevant to the current application state

Making sure all application requests are uniquely named provides some
protection against the application processing a request from another
page which just happened the share the same request name.  It is not a
complete defense as you may receive a request from an old version of
the same page.  A request from an old version of a page is likely to
make reference to values which no longer exist in the server session.

Some online banking applications attempt to avoid this problem by
opening browser windows that do not have history navigation controls.
A user who uses keyboard accelerators for history navigation will not
be hindered by the lack of navigation buttons.

The \texttt{popview} application does not modify any of the data it
uses so there is little scope for submissions from old pages to cause
errors.

By changing the base class for the application object we can gain
support for server side sessions.  Albatross includes a simple session
server and supporting mixin classes.

The new application prologue looks like this:

\begin{verbatim}
#!/usr/bin/python
from albatross import SimpleSessionApp, SessionAppContext
from albatross.cgiapp import Request
import popviewlib
\end{verbatim}

The execution context now inherits from \class{SessionAppContext}:

\begin{verbatim}
class AppContext(SessionAppContext):

    def open_mbox(self):
        if hasattr(self.locals, 'mbox'):
            return
        self.locals.mbox = popviewlib.Mbox(self.locals.username, self.locals.passwd)

    def read_msg(self):
        if hasattr(self.locals, 'msg'):
            return
        self.locals.msg = self.locals.mbox[int(self.locals.msgnum) - 1]
        self.locals.msg.read_body()
\end{verbatim}

And the new application class looks like this:

\begin{verbatim}
class App(SimpleSessionApp):

    def __init__(self):
        SimpleSessionApp.__init__(self,
                                  base_url='popview.py',
                                  template_path='.',
                                  start_page='login',
                                  secret='-=-secret-=-',
                                  session_appid='popview3')
        for page_class in (LoginPage, ListPage, DetailPage):
            self.register_page(page_class.name, page_class())

    def create_context(self):
        return AppContext(self)
\end{verbatim}

The \var{session_appid} argument to the constructor is used to uniquely
identify the application at the server so that multiple applications
can be accessed from the same browser without the session from one
application modifying the session from another.

Apart from changes to load the new template files, we also need to
change the \class{ListPage} class because we changed the method of
selecting messages from the message list.

\begin{verbatim}
class ListPage:

    name = 'list'

    def page_process(self, ctx):
        if ctx.req_equals('msgnum'):
            ctx.set_page('detail')

    def page_display(self, ctx):
        ctx.open_mbox()
        ctx.run_template('list.html')
\end{verbatim}

\section{Building Applications with Page Modules\label{app-popview4}}

Implementing an application as a monolithic program is fine for small
applications.  As the application grows the startup time becomes an
issue, as does maintenance.  Albatross provides a set of classes that
allow you to implement each page in a separate Python module.  In this
section we will convert the \texttt{popview} application to this type
of application.

Converting a monolithic application to a page module application is
usually fairly simple.  First we must turn each page object into a
page module.  When we used page objects, the class that implemented
each page was identified by the \member{name} class member.  With page
modules the name of the module identifies the page that it processes.

The complete sample program is contained in the
\texttt{samples/popview4} directory.  Use the \texttt{install.py}
script to install the sample.

\begin{verbatim}
cd samples/popview4
python install.py
\end{verbatim}

The \class{LoginPage} class becomes \texttt{login.py}.

\verbatiminput{../samples/popview4/login.py}

The \class{ListPage} class becomes \texttt{list.py}.

\verbatiminput{../samples/popview4/list.py}

And the \class{DetailPage} class becomes \texttt{detail.py}.

\verbatiminput{../samples/popview4/detail.py}

When using page modules we do not need to register each page module.
When Albatross needs to locate the code for a page it simply imports
the module.  So the entire \texttt{popview.py} program now looks like
this:

\verbatiminput{../samples/popview4/popview.py}

\section{Using \texttt{mod_python} to Deploy Applications\label{app-popview5}}

In all of the previous sections you will note that all of the programs
used the \class{Request} class from the \module{albatross.cgiapp}
module.  The \module{albatross.apacheapp} module contains a
\class{Request} class to allow you to deploy your application using
\texttt{mod_python} \footnote{For more information on \texttt{mod_python},
including installation instructions, see \url{http://www.modpython.org/}.}.  In
this section we will modify the \texttt{popview.py} application to deploy it
using \texttt{mod_python}.

In theory it is possible to change application deployment method from
CGI to \texttt{mod_python} by changing less than 5 lines of code in
the entire application.  The complete sample program is contained in
the \texttt{samples/popview5} directory.  Use the \texttt{install.py}
script to install the sample.

\begin{verbatim}
cd samples/popview5
python install.py
\end{verbatim}

The new \texttt{popview.py} mainline follows.

\verbatiminput{../samples/popview5/popview.py}

The \function{handler()} function is called by \texttt{mod_python}
when a browser request is received that must be handled by the
program.

You also need to create a \texttt{.htaccess} file to tell Apache to
run the application using \texttt{mod_python}.

\begin{verbatim}
DirectoryIndex popview.py
SetHandler python-program
PythonHandler popview
\end{verbatim}

Assuming you install the popview sample below the \texttt{/var/www}
directory you will need configure Apache settings for the
\texttt{/var/www/alsamp} directory:

\begin{verbatim}
<Directory /var/www/alsamp/>
    AllowOverride FileInfo Indexes
    Order allow,deny
    Allow from all
</Directory>
\end{verbatim}

\section{Random Access Applications\label{app-random}}

In the popview application the server is in complete control of the
sequence of pages that are served to the browser.  In some
applications you want the user to be able to bookmark individual pages
for later retrieval in any desired sequence.  Albatross provides
application classes built with the \class{RandomPageModuleMixin} class
for this very purpose.

The \texttt{random} sample is provided to demonstrate the use of the
\class{RandomModularSessionApp} class.  Use the \texttt{install.py}
script to install the sample.

\begin{verbatim}
cd samples/random
python install.py
\end{verbatim}

The complete mainline of the \texttt{randompage.py} sample is shown below.

\verbatiminput{../samples/random/randompage.py}

When processing the browser request the application determines which
page to serve to the browser by inspecting the URL in the browser
request.  The page identifier is taken from the part of the URL which
follows the \var{base_url} argument to the constructor.  If the page
identifier is empty then the application serves the page identified by
the \var{start_page} argument to the constructor.

If you point your browser at
\mbox{\url{\cgibindir/alsamp/random/randompage.py}} you will notice that
the server has redirected your browser to the start page.

The sample program defines two pages which demonstrate two different
ways to direct user navigation through the application.

The \texttt{tree.html} page template uses a form to capture user
input.

\verbatiminput{../samples/random/pages/tree.html}

During conversion to HTML the \texttt{<al-form>} tag automatically
places the name of the current page into the \texttt{action}
attribute.  This makes the browser send the response back to the same
page module (\texttt{tree.py}).

\verbatiminput{../samples/random/pages/tree.py}

When the application receives the \texttt{paginate} request it uses
the \method{redirect()} method to direct the browser to a new page.

The \texttt{paginate.html} page template uses a URLs to capture user
input.

\verbatiminput{../samples/random/pages/paginate.html}

During conversion to HTML the \texttt{<al-a>} tag automatically
translates the \texttt{href="tree"} attribute into a URL which
requests the \texttt{tree} page from the application.  Since the
browser is doing all of the work, the \texttt{paginate.py} module
which handles the \texttt{paginate} page is very simple.

\verbatiminput{../samples/random/pages/paginate.py}

\section{The Albatross Session Server\label{app-ses-server}}

The Albatross Session server works in concert with the execution context
and application mixin classes in the \module{albatross.session} module to
provide server-side session recording. The application and the server
communicate via TCP sockets. By default, session servers listen on
port 34343.

More than one Albatross application can share a single session server
process, and applications can be deployed over multiple web server
hosts.

\subsection{Sample Simple Session Server\label{app-ses-simple-server}}
The \texttt{albatross.simpleserver} module is a sample session server.
It can either be used stand-alone, or imported into other Python
scripts.

The session server uses TCP sockets to communicate with the
application mixin, by default listening on port 34343.  The server
port can be changed by using the \texttt{-p} or \texttt{--port=}
command line argument.  Internally the server uses a select loop to
allow connections from multiple applications simultaneously.

Note that the daemon does not need to run as \texttt{root}, provided
it listens on a port above 1024. If possible, you should run it under
a user ID not shared by any other processes (and not \texttt{nobody}).
You should also ensure that only authorised clients can connect to
your session server, as the protocol provides no authentication or
authorisation mechanisms.


Application constructor arguments which are relevant to the session
server are:

\begin{itemize}
\item{\var{session_appid}}

This is used to identify the application with the session server.  It
is also used as the session id in the cookie sent to the browser.

\item{\var{session_server}\code{ = 'localhost'}}

If you decide to run the session server on a different machine to the
application you must pass the host name of the session server in this
argument.

\item{\var{server_port}\code{ = 34343}}

If you decide to run the session server on a different port you must
pass the port number in this argument.

\item{\var{session_age}\code{ = 1800}}

This argument defines the amount of time in seconds for which idle
sessions will kept in the server.
\end{itemize}

\subsection{Unix Session Server Daemon\label{app-ses-unix-daemon}}
In the \texttt{session-server} directory of the source distribution is
a Unix daemon version of the \texttt{simpleserver.py} session server,
called \texttt{al-session-daemon}.

Long running server processes under Unix need to be backgrounded,
and disassociated from the terminal device on which they were
started. \texttt{al-session-daemon} provides these functions, as well
as recording the process ID of the daemon so as to allow it to be easily
shut-down.

Note that the daemon does not need to run as \texttt{root}, provided
it listens on a port above 1024, and can write to it's pid and log
directories. If possible, you should run it under a user ID not shared
by any other processes (and not \texttt{nobody}).  You should also ensure
that only authorised clients can connect to your session server, as the
protocol provides no authentication or authorisation mechanisms.

\begin{verbatim}
Usage: al-session-daemon [options]... <command>

Where [options] are:
  -D, --debug                   Write debugging to log
  -h, --help                    Display this help and exit
  -k <pid-file>,                Record server pid in <pid-file>, default is 
    --pidfile=<pid-file>        /var/run/al-session-daemon.pid
  -p <port>, --port=<port>      Listen on <port>, default is 34343
  -l <log-file>,                Write log to <log-file>, default is
    --log=<log-file>            /var/log/al-session-daemon.log

<command> is one of:
  start    start a new daemon
  stop     kill the current daemon
  status   request the daemon's status
\end{verbatim}


\subsection{Server Protocol\label{app-ses-protocol}}

You can see the session server in action by using telnet.

\begin{verbatim}
djc@rat:~$ telnet localhost 34343 
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
new myapp 3600
OK 38b80b3f546c8cfa
put myapp 38b80b3f546c8cfa
OK - send data now, terminate with blank line
here is my session data
it is on multiple lines

OK
get myapp 38b80b3f546c8cfa
OK - session follows
here is my session data
it is on multiple lines

del myapp 38b80b3f546c8cfa
OK
get myapp 38b80b3f546c8cfa
ERROR no such session
quit
Connection closed by foreign host.
djc@rat:~$ 
\end{verbatim}

All dialogue is line based using a CRLF end of line sequence.  Session
ids are generated by the server and each application has its own set
of session ids.  The application mixin class in the
\module{albatross.session} module uses the \var{session_appid}
argument to the constructor as the application id with the session
server.  Note that this application id is also used in the cookie sent
to the browser.

If a command was successful the server response line will start with
the text \texttt{'OK'} otherwise it will start with \texttt{'ERROR'}.

\subsubsection{Create New Session\label{app-proto-new}}

To create a new session for the \var{appid} application which will be
deleted if left idle for more than \var{age} seconds the application
sends a line of the form:

\begin{verbatim}
"new " appid " " age CRLF
\end{verbatim}

Successful response will be a line of the form:

\begin{verbatim}
"OK " sesid CRLF
\end{verbatim}

\subsubsection{Save Session\label{app-proto-put}}

To save data into an existing session the application sends a line of
the form:

\begin{verbatim}
"put " appid " " sesid CRLF
\end{verbatim}

If the session exists in the server it will respond with the following
line:

\begin{verbatim}
"OK - send data now, terminate with blank line" CRLF
\end{verbatim}

The program then sends a sequence of text lines terminated by a single
blank line.  The server then responds with:

\begin{verbatim}
"OK" CRLF
\end{verbatim}

\subsubsection{Retrieve Session\label{app-proto-get}}

To retrieve data for an existing session the application sends a line
of the form:

\begin{verbatim}
"get " appid " " sesid CRLF
\end{verbatim}

If the session exists in the server it will respond with the following
line:

\begin{verbatim}
"OK - session follows" CRLF
\end{verbatim}

The session data saved previously will then be sent terminated by a
single blank line.

\subsubsection{Delete Session\label{app-proto-del}}

To delete an existing session the application sends a line of the
form:

\begin{verbatim}
"del " appid " " sesid CRLF
\end{verbatim}

If the session exists it will be deleted and the server will respond
with the following line:

\begin{verbatim}
"OK" CRLF
\end{verbatim}

\subsubsection{Quit\label{app-proto-quit}}

To disconnect from the server the application sends a line of the form:

\begin{verbatim}
"quit" CRLF
\end{verbatim}

The server will then close the connection.
