DatabaseSessionContainer.py :  » Web-Frameworks » Aquarium » aquarium-2.3 » aquarium » session » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Frameworks » Aquarium 
Aquarium » aquarium 2.3 » aquarium » session » DatabaseSessionContainer.py
"""This is a session module which uses a database backend.

This session module is appropriate for environments such as CGI and mod_python.
This module itself uses different database backends in order to work with
different databases.  aquarium.database.mysql.Session_ comes by default, but
this can easily be ported to other databases.  Please see the appropriate
database module for details such as what tables need to be created.

To use this module, you'll need something like the following in
``AquariumProperties``::

    SESSION_CONTAINER_MODULE = "DatabaseSessionContainer"

    # This is the name of the backend that
    # aquarium.session.DatabaseSessionContainer should use.  This is a module
    # name relative to the database package.

    DATABASE_SESSION_CONTAINER_BACKEND = "mysql.Session"

The following attributes are used:

backend
  This is an instance of the backend.

.. _aquarium.database.mysql.Session:
   aquarium.database.mysql.Session.Session-class.html

"""

__docformat__ = "restructuredtext"

# Created: Fri Jan 14 15:02:39 PST 2005
# Author: Jeffrey Wescott, Shannon -jj Behrens
# Email: jjinux@users.sourceforge.net
#
# Copyright (c) Jeffrey Wescott, Shannon -jj Behrens.  All rights reserved.

import cPickle
import random

from aquarium.session.SessionContainer import SessionContainer,Session
import aquarium.conf.AquariumProperties as properties
from aquarium.database.DatabaseAssistant import MissingRecordError
from aquarium.util.AquariumClass import AquariumClass


class DatabaseSessionContainer(SessionContainer, AquariumClass):

    """This is the session container.

    I won't bother with any locking.  The database can take care of that.

    Concerning aquarium.util.AquariumClass_:  unlike its parent class, this
    class does mixin aquarium.util.AquariumClass and does require a ``ctx``
    parameter in its constructor.  I need to do this in order to get access to
    the database connection.

    The following class level constants are defined:

    SESSION_CLEANUP_FREQUENCY
      If you're using this module, you probably don't have an "application"
      scope.  Hence, it'll be hard for you to create a thread to call
      ``cleanup``.  Hence, I'll call it for you, randomly, every
      SESSION_CLEANUP_FREQUENCY calls to ``open``.  Set this 0 to forgo this
      behavior.

    .. _aquarium.util.AquariumClass:
       aquarium.util.AquariumClass.AquariumClass-class.html

    """

    SESSION_CLEANUP_FREQUENCY = 100

    def __init__(self, ctx):
        """Call ``AquariumClass.__init__``.

        Also, instantiate the ``backend``.

        """
        AquariumClass.__init__(self, ctx)
        self.backend = self._ctx.iLib.aquariumFactory(
            "database." + properties.DATABASE_SESSION_CONTAINER_BACKEND)

    def open(self, sid=None):
        """Create or open a session.

        Also, call ``cleanup`` per ``SESSION_CLEANUP_FREQUENCY``.

        """
        if (self.SESSION_CLEANUP_FREQUENCY and
            random.randint(1, self.SESSION_CLEANUP_FREQUENCY) == 1):
            self.cleanup()
        if sid:
            try:
                return self._loadSession(sid)
            except MissingRecordError:
                pass
        tries = 10
        while 1:
            sid = self._createSid()
            if not self._exists(sid):
                break
            tries -= 1
            if tries <= 0:
                raise OverflowError("Could not create an unused sid")
        return self._createSession(sid)

    def cleanup(self):
        """Delete all of the expired sessions.

        It's the application's responsibility to occasionally call this if you
        set ``SESSION_CLEANUP_FREQUENCY`` to 0.

        """
        self.backend.cleanup()

    def _createSession(self, sid):
        """This is a session factory method."""
        return DatabaseSession(self.backend, sid)

    def _loadSession(self, sid):
        """Load an existing session."""
        session = DatabaseSession(self.backend, sid)
        session.load()
        return session

    def _exists(self, sid):
        """Does a session with the given sid exist?

        This implies that it is not expired.

        """
        return self.backend.exists(sid)

    def _isExpired(self, sid):
        """This is ``NotImplemented`` because it's not needed.

        If it ``_exists``, then it's not expired.

        """
        raise NotImplemented(self._isExpired.__doc__)


class DatabaseSession(Session):

    """This is the session.

    The following attributes are used:

    backend
      This is an instance of the backend.

    """

    def __init__(self, backend, sid):
        """Accept a reference to the backend."""
        self.backend = backend
        Session.__init__(self, sid)

    def save(self):
        """Persist a session to the database.

        This involves pickling the session.  You can change which protocol is
        used to pickle the session by setting the Aquarium property
        ``DATABASE_SESSION_CONTAINER_PICKLE_PROTOCOL``.  It's default value is
        0.  The most optimal setting is ``cPickle.HIGHEST_PROTOCOL``, but that
        doesn't always work.  See the ``proto`` argument of ``cPickle.dumps``
        for more information.

        """
        Session.save(self)
        backend = self.backend
        del self.backend
        try:
            proto = getattr(properties,
                "DATABASE_SESSION_CONTAINER_PICKLE_PROTOCOL", 0)
            pickle = cPickle.dumps(self, proto)
        finally:
            self.backend = backend
        self.backend.save(self, pickle)

    def load(self):
        """Load a session from the database."""
        pickled = self.backend.load(self["sid"])
        self.update(cPickle.loads(pickled))


random.seed()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.