##############################################################################
#
# Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
#   o Redistributions of source code must retain the above copyright
#     notice, this list of conditions, and the disclaimer that follows.
# 
#   o Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions, and the following disclaimer in
#     the documentation and/or other materials provided with the
#     distribution.
# 
#   o Neither the name of Digital Creations nor the names of its
#     contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
# 
# 
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS IS*
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL
# CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
# 
# If you have questions regarding this software, contact:
#
#   Digital Creations, L.C.
#   910 Princess Ann Street
#   Fredericksburge, Virginia  22401
#
#   info@digicool.com
#
#   (540) 371-6909
#
##############################################################################
__doc__='''A very simple HTTP transaction manager.

This module provides a very simple transaction manager for
HTTP requests in a single-threaded application environment.
(Future versions of this module may support multiple transactions.)

This module treats each HTTP request as a transaction.

To use, import the module and then call the 'install' function.
This will install the function 'get_transaction'.  This function will
be used by transactional objects to get the current transaction.

$Id: SingleThreadedTransaction.py,v 1.14 1998/10/23 21:43:38 jim Exp $'''
__version__='$Revision: 1.14 $'[11:-2]

# Install myself before anything else happens:
def get_transaction(): return theTransaction

import __main__ 
__main__.__builtins__.get_transaction=get_transaction


import time, sys

# The following are for backward compatibility:
from PickleDictionary import PickleDictionary
from Persistence import Persistent

class Transactional:
    '''Base class for all transactional objects

    Transactional objects, like persistent objects track
    changes in state.  Unlike persistent objects, transactional
    objects work in conjunction with a transaction manager to manage
    saving state and recovering from errors.
    '''
    def __changed__(self,v=None):
        if v and not self._p_changed:
            try: get_transaction().register(self)
            except: pass
        return Persistence.Persistent.__changed__(self,v)

    def __inform_commit__(self,transaction,start_time):
        self.__save__()

    def __inform_abort__(self,transaction,start_time):
        try: self._p_jar.abort(self,start_time)
        except: pass



class Transaction:
    'Simple transaction objects for single-threaded applications.'
    Aborted='TransactionAborted'
    now=time.time()
    _note=''

    def _clear(self):
        self._objects=[]
        self._append=self._objects.append
        self.now=time.time()

    __init__=_clear

    def abort(self):
        '''Abort the transaction.

        All objects participating in the current transaction will be
        informed of the abort so that they can roll back changes or
        forget pending changes.
        '''
        if self._objects:
            for o in tuple(self._objects):
                try:
                    o.__inform_abort__(self,self.now)
                except: pass
            self._clear()

    _abort=abort

    def begin(self,note=''):
        '''Begin a new transaction.

        This aborts any transaction in progres.
        '''
        if self._objects: self._abort()
        else: self._clear()
        self._note=note

    def note(self,note): self._note=note
        
    def info(self): return "%.3f\t%s" % (self.now,self._note)

    def commit(self):
        'Finalize the transaction'
        try:
            for o in tuple(self._objects):
                o.__inform_commit__(self,self.now)
        except:
            t,v,tb=sys.exc_type, sys.exc_value, sys.exc_traceback
            try:
                self.abort()
                sys.exc_type, sys.exc_value, sys.exc_traceback=t,v,tb
            except: pass
            tb=None
            raise sys.exc_type, sys.exc_value, sys.exc_traceback
        
        self._clear()

    def register(self,object):
        'Register the given object for transaction control.'
        self._append(object)

theTransaction=Transaction()
