[albatross-users] Session management how-to?
Dave Kuhlman
dkuhlman at cutter.rexx.com
Fri Jun 28 06:36:48 EST 2002
On Sun, Jun 23, 2002 at 07:47:43PM +1000, Dave Cole wrote:
>
> > I'm also writing up a few notes, as I learn things, on how-to do
> > things in Albatross. I've attached what I've done so far below.
> > This is preliminary, needless to say; I'm still learning Albatross.
> > But, if you you have any comments, I'm interested. And, if you
> > should feel that this would be of use to other Albatross users
> > (after a bit more work, of course), let me know.
>
> This is enormously valuable. We are not able to do this as we are all
> too close to the code now.
Thanks for comments and encouragement.
I've worked over this how-to document a bit more and made some
additions. I also tried to incorporate your comments. The new
version is appended below. And, I've attached a file containing
the original source (HTML). You can also find it at my Web site
(http://www.rexx.com/~dkuhlman/albatross_index.html).
You are welcome to use it any way you think would be helpful. If
you do decide to use it, let me know and I'll try to help with
converting it to your source format. You use LaTeX2HTML, and
I've used LaTeX/TeX only briefly, so this would be a good learning
experience for me.
[snip]
> If you use the session server then idle sessions are deleted
> automatically. The session server will handle multiple web servers.
> Session management is a non-issue for browser side sessions.
Ah ... I think I've got it. I made a correction to the doc.
[snip]
>
> Small correction; SimpleSessionFileApp and SessionFileAppContext saves
> sessions in the file system while SimpleSessionApp and
> SessionAppContext save sessions in the session server via TCP socket.
>
Not sure that I understand this, but I added it to the doc.
Thanks again for Albatross.
- Dave K
================================================================
Albatross How-to for Beginners
Contents:
* Introduction
* How-to Structure an Object-based Application
* How-to Pass a Value to the Presentation
* How-to Pass a Value to the Controller
* How-to Create a Session-based Application
* How-to Manage Sessions
* How-to Convert an Object App to a Modular App
* Transitions -- How-to Move From Page to Page
Back to top
_________________________________________________________________
Introduction
This document explains how to do a number of simple tasks with
Albatross. It is hoped that it will get a beginning Albatross user
past a number of early questions and problems so that s/he can move on
to more complex tasks.
Back to top
_________________________________________________________________
How-to Structure an Object-based Application
This section describes the structure of an object-based application.
It can be used as a "template" for creating an application.
An object-based application is one
1. Create the presentation -- Create an HTML file for each page. This
is the Albatross template file.
2. Create the controller -- Create a Python script. This script will
contain the following items:
3. Import the needed Albatross classes. For an object-based
application, the following are appropriate:
from albatross import SimpleApp, SimpleAppContext
4. Define a class for each page in the application. Here is a sample:
class Page2:
name = 'page2'
def page_process(self, ctx):
if ctx.req_equals('button_1'):
if ctx.get_value('next_page') == 'page3':
ctx.set_page('page3')
o
o
o
def page_enter(self, ctx):
o
o
o
def page_leave(self, ctx):
o
o
o
def page_display(self, ctx):
o
o
o
ctx.run_template('page2.html')
5. Define a context class as a subclass of SessionAppContext. Here is
a sample:
class AppContext(SimpleAppContext):
def __init__(self, app):
SimpleAppContext.__init__(self, app)
6. Define an application class as a subclass of SimpleSessionApp. The
constructor should call the constructor of the superclass and
register each page (class) in the application. Also provide a
create_context method that creates and returns an instance of your
context class. Here is an example:
class App(SimpleApp):
def __init__(self):
SimpleApp.__init__(self,
base_url = 'dispatch.py',
template_path = '.',
start_page = 'page1',
secret = 'tomato')
for page_class in (Page1, Page2, Page3):
self.register_page(page_class.name, page_class())
def create_context(self):
return AppContext(self)
7. Create the "main" script. Here is a sample:
if __name__ == '__main__':
app = App()
app.run(Request())
Back to top
_________________________________________________________________
How-to Pass a Value to the Presentation
This technique enables you to pass a value from the controller (the
Python script) to the presentation (the HTML file/template).
1. In the controller (i.e. in the Python script), add the value to
the the locals in the context. Here is a sample of the
page_display method in the class defined for the page:
class Page1:
name = 'page1'
def page_display(self, ctx):
ctx.locals.variable_1 = 'a sample value'
ctx.locals.variable_2 = 'another value'
ctx.run_template('page1.html')
2. In the presentation (i.e. the HTML page), use an Albatross tag to
"capture" the value from the context. Here is a sample tag:
<p>Value #1: <al-input name="variable_1"></p>
<p>Value #2: <al-value expr="variable_2"></p>
Back to top
_________________________________________________________________
How-to Pass a Value to the Controller
This technique enables you to capture input from the presentation
(i.e. from the end-user at the Web browser) and pass those values back
to the controller (the Python script).
1. Add "input" items to the presentation (the HTML template):
<p>Enter your name: <al-input type="text" name="user_name"></p>
<p>Enter your name: <input type="text" name="user_phone"></p>
Note that the first item (user_name) also allows you to pass a
value from the controller to the presentation. The second item
(user_phone) does not.
2. Capture the entered values in the controller. Here is a sample
page_display method:
class Page2:
name = 'page1'
def page_process(self, ctx):
user_name = ctx.locals.user_name
user_phone = ctx.locals.user_phone
# Do something with user_name and user_phone.
o
o
o
Back to top
_________________________________________________________________
How-to Create a Session-based Application
This section describes how-to create an application that manages
sessions and saves state across pages (responses) within each session.
Let's suppose that you start with a simple object-based application as
described above.
In order to convert this simple application into a session-based one,
you will need to do the following:
1. Import and inherit from SimpleSessionApp and SessionAppContext
(instead of from SimpleApp and SimpleAppContext) as follows:
from albatross import SimpleSessionApp, SessionAppContext
2. Define your context class as a subclass of SessionAppContext
(instead of AppContext). For example:
class AppContext(SessionAppContext):
def __init__(self, app):
SessionAppContext.__init__(self, app)
3. Define your application class as a subclass of SimpleSessionApp
(instead of SimpleApp). Note that in addition to switching to the
use of SimpleSessionApp, you will also need to add the keyword
argument session_appid. Here is an example:
class App(SimpleSessionApp):
def __init__(self):
SimpleSessionApp.__init__(self,
base_url = 'dispatch.py',
template_path = '.',
start_page = 'page1',
secret = 'tomato',
session_appid = 'sampleapp')
for page_class in (Page1, Page2, Page3):
self.register_page(page_class.name, page_class())
def create_context(self):
return AppContext(self)
4. Start the session server -- In order to run your session
application, you will need to start a session server. Albatross
provides a session server that runs as a daemon. al-session-daemon
is in the subdirectory session-server of the Albatross
distribution. Get help by typing:
./al-session-daemon -h
And, here is an example of how to start it up:
./al-session-daemon -k mysessions.pid start
Back to top
_________________________________________________________________
How-to Manage Sessions
In this section, we explain how to control sessions from within your
application. In particular, we'll describe how to create a new session
and how to remove a session (e.g. when one of your end-users finishes
with your application, and how to save state (values) across pages
within a session.
1. How-to create a session -- Albatross does this for you
automatically. If the request from the browser contains
information about an existing session, that session is used,
otherwise Albatross creates a new session.
2. How-to remove a session -- Albatross will delete idle sessions for
you automatically. However, if you want your end users to be able
to logout or exit from your application, for example, so that they
can start a new session, then you will need to explicitly remove
the session. For example, suppose you have a page from which the
application can go no further. You could remove the session on
entering the page. The user will never leave the page, but
reloading the page will take them back to the beginning. Here is
an example:
class FinalPage:
def page_enter(self, ctx):
ctx.remove_session()
Or, if the final page of your application contains a "Logout" or
"Exit" button, you can remove the session in the page_process
method of the class for that page like this:
class FinalPage:
def page_process(self, ctx):
# Check for the logout button.
if ctx.req_equals('logout'):
ctx.remove_session()
# Send the user back to the login page.
ctx.set_page('login')
3. How-to save session state across pages within the application --
In order to direct Albatross to do this, you will "register" the
variables that you want saved. Do this by calling
add_session_vars, passing the names of the variables to be saved.
Here is an example:
class Page1:
def page_enter(self, ctx):
ctx.add_session_vars('user_name', 'user_phone')
This tells Albatross to preserve these variables across pages. In
Addition, you must also create these variables in the context. In
Python code, the following will work:
ctx.locals.user_name = name
ctx.locals.user_phone = phone
And, in HTML, an input item in a form will create the values.
After doing this, you will be able to access these variables
within the locals of the context object. For example in Python:
name = ctx.locals.user_name
phone = ctx.locals.user_phone
And, since the values are in the local context, you will be able
to reference these variables from your HTML code. For example:
<al-value expr="user_name">
<al-input name="user_phone">
Additional notes on session management:
* In order to run a session based application, you must start-up an
Albatross session server. The session-server sub-directory in the
Albatross distribution, contains an implementation of a session
server (al-session-daemon).
* If your application inherits its context and application classes
from SimpleSessionApp and SessionAppContext then Albatross stores
and saves session information in the session server via TCP
socket.
* In contrast, if your application inherits its context and
application classes from SimpleSessionFileApp and
SessionFileAppContext then Albatross stores and saves session
information in files in the local file system. Note that if you
change from memory-based session storage to file-based storage,
you will need to modify the call to the application superclass
(SimpleSessionFileApp). Add the session_dir keyword argument, with
the directory (a string) where you want Albatross to store session
state.
Back to top
_________________________________________________________________
How-to Convert an Object App to a Modular App
First, let's make clear what we are trying to do here. We are going to
convert an application whose controller is implemented with one class
(object) definition for each page (i.e. an object-based application)
into an application whose controller is implemented with one module
(.py file) for each page (a modular application).
Why would we do this? If the number of pages in your application has
grown large, you may feel that you have too many classes.
We are going to assume that you already have an object-based
application
1. Create a "main" Python file in your application directory. Let's
call it main.py.
2. In main.py, import ModularSessionApp and SessionAppContext:
from albatross import ModularSessionApp, SessionAppContext
If you want your session state stored in the local file system,
rather than in the session server's memory, then use
ModularSessionFileApp and SessionFileAppContext instead. For
example:
from albatross import ModularSessionFileApp, SessionFileAppContext
And, if you want a non-session application, use the ModularApp
class instead.
3. In main.py define a context class as a subclass of
SessionAppContext (or SessionFileAppContext). Here is an example:
class AppContext(SessionAppContext):
def __init__(self, app):
SessionAppContext.__init__(self, app)
4. In main.py define an application class as a subclass of
ModularSessionApp (or ModularSessionFileApp). Here is an example:
class App(ModularSessionApp):
def __init__(self):
ModularSessionApp.__init__(self,
base_url = 'dispatch.py',
module_path = '.',
template_path = '.',
start_page = 'page1',
secret = 'apricot',
session_appid = 'sampleapp')
def create_context(self):
return AppContext(self)
5. In main.py, define the "main" code, which should create and run
the application instance. This code could look like the following:
if __name__ == '__main__':
app = App()
app.run(Request())
6. Now create a Python module for each page in your application. We
will go through this process for a single page. Suppose you have a
page page1.html (the presentation or view) and a class Page1 (the
controller). Then, create a module called page1.py.
7. Copy the class that defines the controller for Page1 into
page1.py. It might look something like the following:
class Page1
name = 'page1'
def page_process(self, ctx):
if ctx.req_equals('button_1'):
ctx.set_page('page2')
elif ctx.req_equals('button_2'):
ctx.set_page('page3')
def page_display(self, ctx):
ctx.run_template('page1.html')
8. Now, again in page1.py, (1) remove the class line and (2) out-dent
the methods so that they are top-level functions in the module.
Also, (3) remove the self argument from each function. It might
now look something like this:
name = 'page1'
def page_process(ctx):
if ctx.req_equals('button_1'):
ctx.set_page('page2')
elif ctx.req_equals('button_2'):
ctx.set_page('page3')
def page_display(ctx):
ctx.run_template('page1.html')
9. Test your new modular application. Your conversion process is
complete.
Back to top
_________________________________________________________________
Transitions -- How-to Move From Page to Page
There are two parts to this question:
1. How do I test the conditions that determine which page is next?
2. How do I transition to the new page?
We'll look at an example that tests several conditions. Here is an
example from an object-based application:
class Page1State:
name = 'Page1'
def page_process(self, ctx):
if ctx.req_equals('Button_1') and \
ctx.get_value('next_page') == 'Page2' and \
ctx.get_value('user_name') != '' and \
ctx.get_value('user_code') > '0' and \
ctx.locals.user_type == 'important':
ctx.set_page('Page2')
elif ctx.req_equals('Button_2') and \
ctx.get_value('next_page') > 'Page3':
ctx.set_page('Page3')
The above example checks to determine whether Button_1 was pressed
and, if so, checks the values of input items next_page, user_name, and
user_code and session variable user_type before transitioning to
Page2. Let's assume that user_type is a variable set in a previous
page and that it was registered with add_session_vars. Notice that
set_page in the context object is called to tell Albatross which page
is next. This is the Albatross mechanism for transitioning from one
page to the next. The argument to set_page is the name passed to
register_page (for object-based applications) or the name of the
Python module for the page (for modular applications).
Now, here is an example from a modular application:
def page_process(ctx):
if ctx.req_equals('Button_0'):
ctx.set_page('Page3')
elif ctx.req_equals('Button_1') and \
ctx.get_value('next_page') == 'Page3':
ctx.set_page('Page3')
elif ctx.req_equals('Button_2') and \
ctx.get_value('next_page') == 'Page4':
ctx.set_page('Page4')
elif ctx.req_equals('Button_3'):
ctx.set_page('Page3')
Notice that this second example (from the modular application) is
similar to the first example (from the object-based application),
except that there are top-level functions in a module instead of
methods in a class.
Back to top
_________________________________________________________________
Last update: 6/27/02
Dave Kuhlman
dkuhlman at rexx.com
http://www.rexx.com/~dkuhlman
--
Dave Kuhlman
dkuhlman at rexx.com
http://www.rexx.com/~dkuhlman
-------------- next part --------------
A non-text attachment was scrubbed...
Name: alba.zip
Type: application/x-zip-compressed
Size: 2814 bytes
Desc: not available
URL: <http://www.object-craft.com.au/pipermail/albatross-users/attachments/20020627/76244b6f/attachment.bin>
More information about the Albatross-users
mailing list