[Erp5-report] r12648 - in /erp5/trunk/products/ERP5Type: TM.py Tool/ClassTool.py

nobody at svn.erp5.org nobody at svn.erp5.org
Tue Feb 13 13:54:20 CET 2007


Author: jp
Date: Tue Feb 13 13:54:17 2007
New Revision: 12648

URL: http://svn.erp5.org?rev=12648&view=rev
Log:
Now transactional to some extent.

Added:
    erp5/trunk/products/ERP5Type/TM.py
Modified:
    erp5/trunk/products/ERP5Type/Tool/ClassTool.py

Added: erp5/trunk/products/ERP5Type/TM.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/TM.py?rev=12648&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Type/TM.py (added)
+++ erp5/trunk/products/ERP5Type/TM.py Tue Feb 13 13:54:17 2007
@@ -1,0 +1,90 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Provide support for linking an external transaction manager with Zope's
+"""
+
+
+class VTM:
+    """Mix-in class that provides transaction management support
+
+    A sub class should call self._register() whenever it performs any
+    transaction-dependent operations (e.g. sql statements).
+
+    The sub class will need to override _finish, to finalize work,
+    _abort, to roll-back work, and perhaps _begin, if any work is
+    needed at the start of a transaction.
+
+    A subclass that uses locking during transaction commit must
+    defined a sortKey() method.
+
+    The VTM variety can be mixed-in with persistent classes.
+    """
+
+    _v_registered=0
+    _v_finalize=0
+
+    def _begin(self): pass
+
+    def _register(self):
+        if not self._v_registered:
+            try:
+                get_transaction().register(Surrogate(self))
+                self._begin()
+                self._v_registered = 1
+                self._v_finalize = 0
+            except: 
+                pass
+
+    def tpc_begin(self, *ignored): pass
+    commit=tpc_begin
+
+    def _finish(self):
+        raise NotImplementedError
+
+    def _abort(self):
+        raise NotImplementedError
+
+    def tpc_vote(self, *ignored):
+        self._v_finalize = 1
+
+    def tpc_finish(self, *ignored):
+        if self._v_finalize:
+            try: 
+                self._finish()
+            finally: 
+                self._v_registered=0
+                self._v_finalize=0
+
+    def abort(self, *ignored):
+        try: 
+            self._abort()
+        finally: 
+            self._v_registered=0
+            self._v_finalize=0
+
+    tpc_abort = abort
+
+    def sortKey(self, *ignored):
+        """ The sortKey method is used for recent ZODB compatibility which
+            needs to have a known commit order for lock acquisition.  Most
+            DA's talking to RDBMS systems do not care about commit order, so
+            return the constant 1
+        """
+        return 1
+
+class Surrogate:
+
+    def __init__(self, db):
+        self._p_jar=db
+        self.__inform_commit__=db.tpc_finish
+        self.__inform_abort__=db.tpc_abort

Modified: erp5/trunk/products/ERP5Type/Tool/ClassTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Tool/ClassTool.py?rev=12648&r1=12647&r2=12648&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Tool/ClassTool.py (original)
+++ erp5/trunk/products/ERP5Type/Tool/ClassTool.py Tue Feb 13 13:54:17 2007
@@ -33,8 +33,9 @@
 from AccessControl import ClassSecurityInfo
 from Globals import InitializeClass, DTMLFile
 from App.config import getConfiguration
+from Products.ERP5Type.TM import VTM as TM
 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-import os
+import os, tempfile
 
 from Products.ERP5Type import Permissions
 from Products.ERP5Type import _dtmldir
@@ -65,14 +66,18 @@
   ClassTool.
 """
 
+COPYRIGHT = "Copyright (c) 2002-2007 Nexedi SARL and Contributors. All Rights Reserved."
+LOCAL_DIRECTORY_LIST = ('Document', 'Extensions', 'Constraint', 'tests', 'PropertySheet')
+
 if allowClassTool():
 
-  class ClassTool(BaseTool):
+  class ClassTool(TM, BaseTool):
       """
         This is the full-featured version of ClassTool.
       """
       id = 'portal_classes'
       meta_type = 'ERP5 Class Tool'
+      _use_TM = _transactions = 1
   
       # Declarative Security
       security = ClassSecurityInfo()
@@ -211,7 +216,7 @@
         text = """\
 ##############################################################################
 #
-# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
+# %s
 #
 # WARNING: This program as such is intended to be used by professional
 # programmers who take the whole responsability of assessing all potential
@@ -258,8 +263,8 @@
                       , PropertySheet.XMLObject
                       , PropertySheet.CategoryCore
                       , PropertySheet.DublinCore
-                      )""" % class_id
-        writeLocalDocument(class_id, text)
+                      )""" % (COPYRIGHT, class_id)
+        self.writeLocalDocument(class_id, text)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editDocumentForm?class_id=%s&message=Document+Created' % (self.absolute_url(), class_id))
   
@@ -269,7 +274,7 @@
           Updates a Document with a new text
         """
         previous_text = readLocalDocument(class_id)
-        writeLocalDocument(class_id, text, create=0)
+        self.writeLocalDocument(class_id, text, create=0)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editDocumentForm?class_id=%s&message=Document+Saved' % (self.absolute_url(), class_id))
   
@@ -306,7 +311,7 @@
         text = """\
 ##############################################################################
 #
-# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
+# %s
 #
 # WARNING: This program as such is intended to be used by professional
 # programmers who take the whole responsability of assessing all potential
@@ -344,8 +349,8 @@
     )
   
 
-"""
-        writeLocalPropertySheet(class_id, text)
+""" % COPYRIGHT
+        self.writeLocalPropertySheet(class_id, text)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editPropertySheetForm?class_id=%s&message=PropertySheet+Created' % (self.absolute_url(), class_id))
   
@@ -355,7 +360,7 @@
           Updates a PropertySheet with a new text
         """
         previous_text = readLocalPropertySheet(class_id)
-        writeLocalPropertySheet(class_id, text, create=0)
+        self.writeLocalPropertySheet(class_id, text, create=0)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editPropertySheetForm?class_id=%s&message=PropertySheet+Saved' % (self.absolute_url(), class_id))
   
@@ -390,7 +395,7 @@
         text = """\
 ##############################################################################
 #
-# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
+# %s
 #
 # WARNING: This program as such is intended to be used by professional
 # programmers who take the whole responsability of assessing all potential
@@ -417,8 +422,8 @@
 
 def myExtensionMethod(self, param=None):
   pass
-"""
-        writeLocalExtension(class_id, text)
+""" % COPYRIGHT
+        self.writeLocalExtension(class_id, text)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editExtensionForm?class_id=%s&message=Extension+Created' % (self.absolute_url(), class_id))
   
@@ -428,7 +433,7 @@
           Updates a Extension with a new text
         """
         previous_text = readLocalExtension(class_id)
-        writeLocalExtension(class_id, text, create=0)
+        self.writeLocalExtension(class_id, text, create=0)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editExtensionForm?class_id=%s&message=Extension+Saved' % (self.absolute_url(), class_id))
   
@@ -447,7 +452,7 @@
         text = '''\
 ##############################################################################
 #
-# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
+# %s
 #
 # WARNING: This program as such is intended to be used by professional
 # programmers who take the whole responsability of assessing all potential
@@ -519,8 +524,8 @@
     are defined in /usr/lib/python/unittest.py.
     """
     self.assertEqual(0, 1)
-'''
-        writeLocalTest(class_id, text)
+''' % COPYRIGHT
+        self.writeLocalTest(class_id, text)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editTestForm?class_id=%s&message=Test+Created' % (self.absolute_url(), class_id))
   
@@ -530,7 +535,7 @@
           Updates a Test with a new text
         """
         previous_text = readLocalTest(class_id)
-        writeLocalTest(class_id, text, create=0)
+        self.writeLocalTest(class_id, text, create=0)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editTestForm?class_id=%s&message=Test+Saved' % (self.absolute_url(), class_id))
   
@@ -553,7 +558,7 @@
         text = """\
 ##############################################################################
 #
-# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
+# %s
 #
 # WARNING: This program as such is intended to be used by professional
 # programmers who take the whole responsability of assessing all potential
@@ -597,8 +602,8 @@
       # Do the job here
       
       return errors
-"""
-        writeLocalConstraint(class_id, text)
+""" % COPYRIGHT
+        self.writeLocalConstraint(class_id, text)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editConstraintForm?class_id=%s&message=Constraint+Created' % (self.absolute_url(), class_id))
 
@@ -608,7 +613,7 @@
           Updates a Constraint with a new text
         """
         previous_text = readLocalConstraint(class_id)
-        writeLocalConstraint(class_id, text, create=0)
+        self.writeLocalConstraint(class_id, text, create=0)
         if REQUEST is not None:
           REQUEST.RESPONSE.redirect('%s/manage_editConstraintForm?class_id=%s&message=Constraint+Saved' % (self.absolute_url(), class_id))
 
@@ -696,7 +701,7 @@
           text = '''\
 ##############################################################################
 #
-# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
+# %s
 #                    Yoshinori Okuji <yo at nexedi.com>
 #
 # WARNING: This program as such is intended to be used by professional
@@ -741,7 +746,7 @@
                          portal_tools = (),
                          content_constructors = (),
                          content_classes = ())
-'''
+''' % s
           f = open(init, 'w')
           try:
             f.write(text)
@@ -840,6 +845,85 @@
         dochelper.setStaticPropertyList(property_list)
         return dochelper
 
+      # Transaction Management
+      def createTemporaryInstanceHome(self):
+        """
+        """
+        self._register()
+        # Make a new instance home
+        if not getattr(self, '_v_instance_home', None):
+          self._v_instance_home = tempfile.mkdtemp()
+          instance_home = self._v_instance_home
+          for name in LOCAL_DIRECTORY_LIST:
+            os.mkdir(os.sep.join((instance_home, name)))
+
+      def deleteTemporaryInstanceHome(self):
+        """
+        """
+        # Delete the whole instance home
+        if getattr(self, '_v_instance_home', None):
+          tmp_instance_home = self._v_instance_home
+          for name in LOCAL_DIRECTORY_LIST:
+            source_dir = os.sep.join((tmp_instance_home, name))
+            for fname in os.listdir(source_dir):
+              source_file = os.sep.join((source_dir,fname))
+              os.remove(source_file)
+            os.rmdir(source_dir)
+          os.rmdir(tmp_instance_home)
+        self._v_instance_home = None
+
+      def renameTemporaryInstanceHome(self):
+        """
+        """
+        # Delete temporary instance home
+        tmp_instance_home = self._v_instance_home
+        instance_home = getConfiguration().instancehome
+        for name in LOCAL_DIRECTORY_LIST:
+          source_dir = os.sep.join((tmp_instance_home, name))
+          destination_dir = os.sep.join((instance_home, name))
+          for fname in os.listdir(source_dir):
+            source_file = os.sep.join((source_dir,fname))
+            destination_file = os.sep.join((destination_dir,fname))
+            try:
+              os.remove(destination_file)
+            except OSError:
+              pass
+            os.rename(source_file, destination_file)
+        self.deleteTemporaryInstanceHome()
+
+      security.declareProtected( Permissions.ManageExtensions, 'writeLocalPropertySheet' )
+      def writeLocalPropertySheet(self, class_id, text, create=1):
+        self.createTemporaryInstanceHome()
+        writeLocalPropertySheet(class_id, text, create=create, instance_home=self._v_instance_home)
+
+      security.declareProtected( Permissions.ManageExtensions, 'writeLocalExtension' )
+      def writeLocalExtension(self, class_id, text, create=1):
+        self.createTemporaryInstanceHome()
+        writeLocalExtension(class_id, text, create=create, instance_home=self._v_instance_home)
+
+      security.declareProtected( Permissions.ManageExtensions, 'writeLocalTest' )
+      def writeLocalTest(self, class_id, text, create=1):
+        self.createTemporaryInstanceHome()
+        writeLocalTest(class_id, text, create=create, instance_home=self._v_instance_home)
+
+      security.declareProtected( Permissions.ManageExtensions, 'writeLocalDocument' )
+      def writeLocalDocument(self, class_id, text, create=1):
+        self.createTemporaryInstanceHome()
+        writeLocalDocument(class_id, text, create=create, instance_home=self._v_instance_home)
+
+      security.declareProtected( Permissions.ManageExtensions, 'writeLocalConstraint' )
+      def writeLocalConstraint(self, class_id, text, create=1):
+        self.createTemporaryInstanceHome()
+        writeLocalConstraint(class_id, text, create=create, instance_home=self._v_instance_home)
+
+      def _finish(self):
+        # Move all temp files we created
+        self.renameTemporaryInstanceHome()
+
+      def _abort(self):
+        # Delete all temp files we created
+        self.deleteTemporaryInstanceHome()
+
 else:
 
   class ClassTool(BaseTool):
@@ -856,3 +940,4 @@
       manage_overview = DTMLFile( 'explainDummyClassTool', _dtmldir )
 
 InitializeClass(ClassTool)
+




More information about the Erp5-report mailing list