    import os
    from glob import glob
    import threading

    from SessionStore import SessionStore

    debug = 0

    class SessionFileStore(SessionStore):
        """A session file store.

        Stores the sessions on disk in the Sessions/ directory,
        one file per session.

        This is useful for various situations:
            1. Using the OneShot adapter
            2. Doing development (so that restarting the app server won't
               lose session information).
            3. Fault tolerance
            4. Clustering

        Note that the last two are not yet supported by WebKit.

        """

        ## Init ##

        def __init__(self, app):
            SessionStore.__init__(self, app)
            self._sessionDir = app._sessionDir
            self._lock = threading.RLock()

        ## Access ##

        def __len__(self):
            if debug:
                print '>> len', len(self.keys())
            return len(self.keys())

        def __getitem__(self, key):
            if debug:
                print '>> get (%s)' % key
            filename = self.filenameForKey(key)
            self._lock.acquire()
            try:
                try:
                    file = open(filename, 'rb')
                except IOError:
                    raise KeyError, key
                try:
                    try:
                        item = self.decoder()(file)
                    finally:
                        file.close()
                except Exception: # session can't be unpickled
                    os.remove(filename) # remove session file
                    print "Error loading session from disk:", key
                    self.application().handleException()
                    raise KeyError, key
            finally:
                self._lock.release()
            return item

        def __setitem__(self, key, item):
            # @@ 2001-11-12 ce: It's still possible that two threads are updating
            # the same session as the same time (due to the user having two windows
            # open) in which case one will clobber the results of the other!
            # Probably need file locking to solve this.
            # @@ 2001-11-16 gat: In order to avoid sessions clobering each other,
            # you'd have to lock the file for the entire time that the servlet is
            # manipulating the session, which would block any other servlets from
            # using that session. Doesn't seem like a great solution to me.
            if debug:
                print '>> setitem(%s, %s)' % (key, item)
            filename = self.filenameForKey(key)
            self._lock.acquire()
            try:
                try:
                    file = open(filename, 'wb')
                    try:
                        try:
                            self.encoder()(item, file)
                        finally:
                            file.close()
                    except Exception:
                        os.remove(filename) # remove file because it is corrupt
                        raise
                except Exception: # error pickling the session
                    print "Error saving session to disk:", key
                    self.application().handleException()
            finally:
                self._lock.release()

        def __delitem__(self, key):
            filename = self.filenameForKey(key)
            if not os.path.exists(filename):
                raise KeyError, key
            sess = self[key]
            if not sess.isExpired():
                sess.expiring()
            os.remove(filename)

        def removeKey(self, key):
            filename = self.filenameForKey(key)
            try:
                os.remove(filename)
            except Exception:
                pass

        def has_key(self, key):
            return os.path.exists(self.filenameForKey(key))

        def keys(self):
            start = len(self._sessionDir) + 1
            end = -len('.ses')
            keys = glob(os.path.join(self._sessionDir, '*.ses'))
            keys = map(lambda key, start=start, end=end: key[start:end], keys)
            if debug:
                print '>> keys =', keys
            return keys

        def clear(self):
            for filename in glob(os.path.join(self._sessionDir, '*.ses')):
                os.remove(filename)

        def setdefault(self, key, default):
            if debug:
                print '>> setdefault (%s, %s)' % (key, default)
            self._lock.acquire()
            try:
                try:
                    return self[key]
                except KeyError:
                    self[key] = default
                    return default
            finally:
                self._lock.release()

        ## Application support ##

        def storeSession(self, session):
            key = session.identifier()
            self[key] = session

        def storeAllSessions(self):
            pass

        ## Self utility ##

        def filenameForKey(self, key):
            return os.path.join(self._sessionDir, '%s.ses' % key)