[Zope-CVS] CVS: Products/DBTab - CHANGES.txt:1.9 DBTab.py:1.11 MountedObject.py:1.6 dbtab.conf.in:1.8

Shane Hathaway shane@zope.com
Fri, 18 Apr 2003 22:15:30 -0400


Update of /cvs-repository/Products/DBTab
In directory cvs.zope.org:/tmp/cvs-serv8943

Modified Files:
	CHANGES.txt DBTab.py MountedObject.py dbtab.conf.in 
Log Message:
Using the product registry turned out to be a bad idea, since objects might
need to be constructed before Zope finishes initialization (for example,
if you're using DBTab to share session data.)  So container_factory was
renamed container_class and you can now create instances of a certain class
in order to mount a database.  The class constructor must accept one
argument, the ID of the object.


=== Products/DBTab/CHANGES.txt 1.8 => 1.9 ===
--- Products/DBTab/CHANGES.txt:1.8	Wed Apr 16 15:59:24 2003
+++ Products/DBTab/CHANGES.txt	Fri Apr 18 22:15:29 2003
@@ -6,7 +6,7 @@
   - Removed import of AdaptableStorage.  Argument converters now work
     when you specify the full module of a storage class.
 
-  - You can now specify a container_factory to generate folderish
+  - You can now specify a container_class to generate folderish
     objects other than standard folders when mounting a new database.
     See dbtab.conf.in.
 


=== Products/DBTab/DBTab.py 1.10 => 1.11 ===
--- Products/DBTab/DBTab.py:1.10	Wed Apr 16 15:59:24 2003
+++ Products/DBTab/DBTab.py	Fri Apr 18 22:15:29 2003
@@ -51,7 +51,7 @@
 
     # Mount options
     mount_paths = None        # ((virtual_path, real_root, real_path),)
-    container_factory = None  # string: "product_name:factory_name"
+    container_class = None    # string: "module_name:class_name"
 
     # Other options
     class_factory = None
@@ -174,7 +174,7 @@
 
         # Read string parameters
         for key in (
-            'class_factory', 'container_factory',
+            'class_factory', 'container_class',
             ):
             if args.has_key(key):
                 setattr(self, key, args[key])
@@ -235,13 +235,13 @@
         return self.open_at_startup
 
     def getMountParams(self, mount_path):
-        """Returns (real_root, real_path, container_factory) for a virtual
+        """Returns (real_root, real_path, container_class) for a virtual
         mount path.
         """
         if self.mount_paths:
             for (virtual_path, real_root, real_path) in self.mount_paths:
                 if virtual_path == mount_path:
-                    return (real_root, real_path, self.container_factory)
+                    return (real_root, real_path, self.container_class)
         raise LookupError('Nothing known about mount path %s' % mount_path)
 
 


=== Products/DBTab/MountedObject.py 1.5 => 1.6 ===
--- Products/DBTab/MountedObject.py:1.5	Wed Apr 16 15:59:24 2003
+++ Products/DBTab/MountedObject.py	Fri Apr 18 22:15:29 2003
@@ -23,7 +23,6 @@
 from AccessControl.ZopeGuards import guarded_getattr
 from OFS.SimpleItem import SimpleItem
 from OFS.Folder import Folder
-from App.FactoryDispatcher import ProductDispatcher
 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
 
 from Mount import MountPoint
@@ -41,38 +40,29 @@
     return configuration
 
 
-class Trailblazer:
-    """Follows Zope paths.  If a path is not found, creates it."""
+class SimpleTrailblazer:
+    """Follows Zope paths.  If a path is not found, creates a Folder.
 
-    def __init__(self, base, zope_app=None, container_factory=None):
+    Respects Zope security.
+    """
+
+    restricted = 1
+
+    def __init__(self, base):
         self.base = base
-        if zope_app is None:
-            zope_app = base
-        self.zope_app = zope_app
-        if not container_factory:
-            container_factory = 'OFSP:manage_addFolder'
-        self.product_name, self.factory_name = container_factory.split(':', 1)
-
-    def _construct(self, context, restricted, id):
-        """Returns the FactoryDispatcher for context."""
-        pd = ProductDispatcher().__of__(context)
-        # Make the installed products available to the product dispatcher
-        pd._getProducts = self.zope_app._getProducts
-        dispatcher = pd[self.product_name]
-        if restricted:
-            factory = guarded_getattr(dispatcher, self.factory_name)
-            factory(id)
-            o = context.restrictedTraverse(id)
-        else:
-            factory = getattr(dispatcher, self.factory_name)
-            factory(id)
-            o = context.unrestrictedTraverse(id)
+
+    def _construct(self, context, id, final):
+        """Creates and returns the named folder."""
+        dispatcher = guarded_getattr(context, 'manage_addProduct')['OFSP']
+        factory = guarded_getattr(dispatcher, 'manage_addFolder')
+        factory(id)
+        o = context.restrictedTraverse(id)
         # Commit a subtransaction to assign the new object to
         # the correct database.
         get_transaction().commit(1)
         return o
 
-    def traverseOrConstruct(self, path, omit_final=0, restricted=1):
+    def traverseOrConstruct(self, path, omit_final=0):
         """Traverses a path, constructing it if necessary."""
         container = self.base
         parts = filter(None, path.split('/'))
@@ -82,15 +72,49 @@
             parts = parts[:-1]
         for part in parts:
             try:
-                if restricted:
+                if self.restricted:
                     container = container.restrictedTraverse(part)
                 else:
                     container = container.unrestrictedTraverse(part)
             except (KeyError, AttributeError):
                 # Try to create a container in this place.
-                container = self._construct(container, restricted, part)
+                container = self._construct(container, part)
         return container
 
+    
+class CustomTrailblazer (SimpleTrailblazer):
+    """Like SimpleTrailblazer but creates custom objects.
+
+    Does not respect Zope security because this may be invoked before
+    security and products get initialized.
+    """
+
+    restricted = 0
+
+    def __init__(self, base, container_class=None):
+        self.base = base
+        if not container_class:
+            container_class = 'OFS.Folder.Folder'
+        pos = container_class.rfind('.')
+        if pos < 0:
+            raise ValueError("Not a valid container_class: %s" % repr(
+                container_class))
+        self.module_name = container_class[:pos]
+        self.class_name = container_class[pos + 1:]
+
+    def _construct(self, context, id):
+        """Creates and returns the named object."""
+        jar = self.base._p_jar
+        klass = jar.db()._classFactory(jar, self.module_name, self.class_name)
+        obj = klass(id)
+        obj._setId(id)
+        context._setObject(id, obj)
+        obj = context.unrestrictedTraverse(id)
+        # Commit a subtransaction to assign the new object to
+        # the correct database.
+        get_transaction().commit(1)
+        return obj
+
 
 class MountedObject(MountPoint, SimpleItem):
     '''A MountPoint with a basic interface for displaying the
@@ -142,17 +166,19 @@
         params = self._v_mount_params
         if params is None:
             params = self._loadMountParams()
-        real_root, real_path, container_factory = params
+        real_root, real_path, container_class = params
         if real_root is None:
             real_root = 'Application'
         try:
             obj = root[real_root]
         except KeyError:
-            if container_factory or self._create_mount_points:
+            if container_class or self._create_mount_points:
                 # Create a database automatically.
                 from OFS.Application import Application
                 obj = Application()
                 root[real_root] = obj
+                # Get it into the database
+                get_transaction().commit(1)
             else:
                 raise
 
@@ -162,10 +188,9 @@
             try:
                 obj = obj.unrestrictedTraverse(real_path)
             except (KeyError, AttributeError):
-                if container_factory or self._create_mount_points:
-                    zopeapp = mount_parent.getPhysicalRoot()
-                    blazer = Trailblazer(obj, zopeapp, container_factory)
-                    obj = blazer.traverseOrConstruct(real_path, restricted=0)
+                if container_class or self._create_mount_points:
+                    blazer = CustomTrailblazer(obj, container_class)
+                    obj = blazer.traverseOrConstruct(real_path)
                 else:
                     raise
         return obj
@@ -252,7 +277,7 @@
         mo._create_mount_points = not not create_mount_points
         # Raise an error now if there is any problem.
         mo._test(app)
-        blazer = Trailblazer(app)
+        blazer = SimpleTrailblazer(app)
         container = blazer.traverseOrConstruct(path, omit_final=1)
         mo._p_jar = container._p_jar
         loaded = mo.__of__(container)


=== Products/DBTab/dbtab.conf.in 1.7 => 1.8 ===
--- Products/DBTab/dbtab.conf.in:1.7	Wed Apr 16 15:59:24 2003
+++ Products/DBTab/dbtab.conf.in	Fri Apr 18 22:15:29 2003
@@ -131,7 +131,7 @@
 # [Database: Sessions]
 # connection_class=LowConflictConnection
 # mount_paths=/temp_folder
-# container_factory=OFSP:manage_addFolder
+# container_class=OFS.Folder.Folder
 
 
 ######################################################################
@@ -248,24 +248,24 @@
 
 # mount_paths=/MyApp/MyCalendar:~Calendar/
 
-## The container_factory parameter lets you choose what kind of
-## objects to create when mounting the database.  By default, DBTab
-## makes Folder objects in the mounted database, but you can use this
-## parameter to create PortalFolders or other kinds of objects
-## instead.  Its format is <product name>:<factory name>.  This
-## parameter is also useful when using volatile data storage such as
-## DemoStorage or MappingStorage.  Since the database gets wiped out
-## when the process stops, the mountable object needs to be created
-## again upon restart.  If you specify a container_factory, the
+## The container_class parameter lets you choose what kind of objects
+## to create when mounting the database for the first time.  By
+## default, DBTab makes Folder objects in the mounted database, but
+## you can use this parameter to create PortalFolders or other kinds
+## of objects instead.  Its format is <module name>.<class name>.
+## This parameter is also useful when using volatile data storage such
+## as DemoStorage or MappingStorage.  Since the database gets wiped
+## out when the process stops, the mountable object needs to be
+## created again upon restart.  If you specify a container_class, the
 ## mountable object will be created automatically after restart.
 
-# container_factory=OFSP:manage_addFolder
+# container_class=OFS.Folder.Folder
 
 ## Another example:
 
-# container_factory=CMFCore:manage_addPortalFolder
+# container_class=Products.CMFCore.PortalFolder.PortalFolder
 
-## Note that container_factory replaces the old auto_create option,
+## Note that container_class replaces the old auto_create option,
 ## which is deprecated as of DBTab 1.2.
 
 ## The class_factory parameter is an advanced option that tells ZODB