[Zope-CVS] CVS: Products/AdaptableStorage - StorageTypesConfiguration.py:1.1 Zope2Mapper.py:1.1 doc.txt:1.1 Zope2FS.py:1.13 Zope2SQL.py:1.5 __init__.py:1.6

Shane Hathaway shane@zope.com
Mon, 23 Dec 2002 23:30:02 -0500


Update of /cvs-repository/Products/AdaptableStorage
In directory cvs.zope.org:/tmp/cvs-serv30532

Modified Files:
	Zope2FS.py Zope2SQL.py __init__.py 
Added Files:
	StorageTypesConfiguration.py Zope2Mapper.py doc.txt 
Log Message:
Provided a way to configure ObjectMappers, with the intent of making
AdaptableStorage easier to explain.  Added IConfigurableObjectMapper
and converted all the mapper setup code to use it.  Included a
checkConfiguration() method which validates the entire object mapper
tree.  Then converted the DBTab-based configuration to use a mapper
factory, which can point to any mapper factory function installed
anywhere.  Tangents to this:

- Refactored Zope2FS and Zope2SQL to use the same code for setting up
mappers, leaving "holes" for the gateways.

- Added connect() and close() methods to ITPCConnection (which doesn't
technically exist yet since I need to choose a name for it. ;-) )

- Factored out common parts of the SQL gateways.

- Implemented the newKey() method of IKeyedObjectSystem, which will
help ZEO environments, in theory.



=== Added File Products/AdaptableStorage/StorageTypesConfiguration.py ===
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""Configuration of storage types for DBTab/ZODB

$Id: StorageTypesConfiguration.py,v 1.1 2002/12/24 04:29:30 shane Exp $
"""

def convertASStorageArgs(name, factory=None, **kw):
    from zodb.public import callMapperFactory, StaticResource
    if factory is None:
        raise RuntimeError('factory is required')
    mapper, conns = callMapperFactory(factory, kw)
    return {
        'mapper_resource': StaticResource(mapper),
        'tpc_conns': conns,
        'name': name,
        }

try:
    from Products.DBTab.StorageTypes import storage_types
    from Products.DBTab.DBTab import database_types
except ImportError:
    pass
else:
    storage_types['ASStorage'] = ('Products.AdaptableStorage.zodb.public',
                                  convertASStorageArgs)
    database_types['ASDB'] = 'Products.AdaptableStorage.zodb.public'



=== Added File Products/AdaptableStorage/Zope2Mapper.py ===
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""A basic mapping from Zope 2 objects to some storage.

$Id: Zope2Mapper.py,v 1.1 2002/12/24 04:29:30 shane Exp $
"""


from serial.public \
     import ObjectSerializer, ObjectGateway, ObjectMapper
from serial_std.public \
     import RollCall, FixedPersistentMapping, IgnoredAttribute, \
     AnyObjectSerializer, StringDataAttribute
from serial_ofs.public \
     import FolderItems, FolderItemsByKeychain, MetaTypeClassifier, \
     IdAttribute, FilePData
from zodb.public import RemainingState


def createZope2Mapper(app_key, stored_keychains):
    """Returns a mapper tree for Zope 2 objects (without any gateways)."""

    # Create and configure the root mapper
    root_mapper = ObjectMapper()
    classifier = MetaTypeClassifier()
    root_mapper.setClassifier(classifier)
    s = ObjectSerializer('Persistence', 'PersistentMapping')
    aspect = FixedPersistentMapping()
    aspect.add('Application', (app_key,), ('OFS.Application.Application',))
    s.addAspect('items', aspect)
    s.addAspect('roll_call', RollCall())
    root_mapper.setSerializer(s)
    root_mapper.setGateway(ObjectGateway())  # No storage necessary

    if stored_keychains:
        folder_items_aspect = FolderItemsByKeychain()
    else:
        folder_items_aspect = FolderItems()

    # folder mapper
    m = root_mapper.addSubMapper('OFS.Folder.Folder')
    s = ObjectSerializer('OFS.Folder', 'Folder')
    m.setSerializer(s)
    s.addAspect('items', folder_items_aspect)
    s.addAspect('id', IdAttribute())
    s.addAspect('remainder', RemainingState())
    classifier.registerDefaultLoader('Folder', 'OFS.Folder.Folder', 1)

    # file mapper
    m = root_mapper.addSubMapper('OFS.Image.File')
    s = ObjectSerializer('OFS.Image', 'File')
    m.setSerializer(s)
    s.addAspect('id', IdAttribute())
    s.addAspect('data', FilePData())
    s.addAspect('remainder', RemainingState())
    classifier.registerDefaultLoader('File', 'OFS.Image.File', 0)

    # image mapper
    m = root_mapper.addSubMapper('OFS.Image.Image')
    s = ObjectSerializer('OFS.Image', 'Image')
    m.setSerializer(s)
    s.addAspect('id', IdAttribute())
    s.addAspect('data', FilePData())
    s.addAspect('remainder', RemainingState())
    classifier.register('Image', 'OFS.Image.Image', (
        '.gif', '.jpg', '.jpeg', '.png'))

    # page template mapper
    m = root_mapper.addSubMapper('ZopePageTemplate')  # abbreviated name
    s = ObjectSerializer('Products.PageTemplates.ZopePageTemplate',
                         'ZopePageTemplate')
    m.setSerializer(s)
    s.addAspect('text', StringDataAttribute('_text'))
    s.addAspect('id', IdAttribute())
    s.addAspect('remainder', RemainingState())
    classifier.register('Page Template', 'ZopePageTemplate', (
        '.pt', '.zpt', '.html'))

    # anyfolder mapper
    m = root_mapper.addSubMapper('anyfolder')
    s = AnyObjectSerializer()
    m.setSerializer(s)
    s.addAspect('items', folder_items_aspect)
    s.addAspect('id', IdAttribute())
    s.addAspect('remainder', RemainingState())
    classifier.registerDefaultStorage('(folderish object)', 'anyfolder', 1)

    # anyfile mapper
    m = root_mapper.addSubMapper('anyfile')
    s = AnyObjectSerializer()
    m.setSerializer(s)
    s.addAspect('id', IdAttribute())
    s.addAspect('remainder', RemainingState())
    classifier.registerDefaultStorage('(fileish object)', 'anyfile', 0)

    # application mapper
    m = root_mapper.addSubMapper('OFS.Application.Application')
    s = ObjectSerializer('OFS.Application', 'Application')
    m.setSerializer(s)
    s.addAspect('items', folder_items_aspect)
    s.addAspect('remainder', RemainingState())
    classifier.registerKey(
        'Application', 'OFS.Application.Application', app_key)

    # Other stuff
    classifier.register('CMF Skins Tool', 'anyfile')  # XXX workaround

    return root_mapper



=== Added File Products/AdaptableStorage/doc.txt ===

AdaptableStorage is a framework for mapping Python objects to
arbitrary databases and formats.  It is based on a system of
interchangeable components that can be extended or replaced.  It is an
enhancement for ZODB, but its components can also be used
independently of ZODB.

At this time, AdaptableStorage comes with two default mappings, a
Zope2-filesystem mapping and a Zope2-PostgreSQL mapping.  These
mappings demonstrate AdaptableStorage and provide the pattern for
creating your own mappings.

AdaptableStorage uses a tree of object mappers to map objects to
databases.  Object mappers serialize, deserialize, store, load,
classify, and identify objects.  Object mappers and their associated
components are reusable for many applications needing to store and
load objects, but the framework is especially designed for mapping
persistent object systems like ZODB.


** Leave "holes" in object mappers to allow separation of gateway and
   serialization.  **



Most object mappers are responsible for loading and storing instances
of one class.  Object mappers separate serialization from storage,
making it possible to reuse serializers with many storage backends.



Object mappers can also optionally implement subobject classification,
sub-mapper access, and key generation.  





=== Products/AdaptableStorage/Zope2FS.py 1.12 => 1.13 ===
--- Products/AdaptableStorage/Zope2FS.py:1.12	Fri Dec 13 15:42:02 2002
+++ Products/AdaptableStorage/Zope2FS.py	Mon Dec 23 23:29:30 2002
@@ -17,179 +17,70 @@
 """
 
 
-from serial.public \
-     import ObjectSerializer, ObjectGateway, ObjectMapper
-from serial_std.public \
-     import RollCall, FixedPersistentMapping, IgnoredAttribute, \
-     PathKeychainGenerator, AnyObjectSerializer, \
-     StringDataAttribute
-from serial_ofs.public import FolderItems, MetaTypeClassifier, IdAttribute, \
-     FilePData
+from serial.public import ObjectGateway
+from serial_std.public import PathKeychainGenerator
 from gateway_fs.public import FSConnection, FSDirectoryItems, FSAutoId, \
      FSSectionData, FSClassificationSection, FSFileData
-from zodb.public import RemainingState
 
+from Zope2Mapper import createZope2Mapper
 
-def createMapper(basepath, volatile=1):
-    fs_conn = FSConnection(basepath)
-
-    object_serializers = {}
-    object_gateways = {}
-
-    # SERIALIZERS
 
-    # folder serializer
-    s = ObjectSerializer('OFS.Folder', 'Folder')
-    s.addAspect('items', FolderItems())
-    s.addAspect('id', IdAttribute())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['OFS.Folder.Folder'] = s
-
-    # page template serializer
-    s = ObjectSerializer('Products.PageTemplates.ZopePageTemplate',
-                         'ZopePageTemplate')
-    s.addAspect('text', StringDataAttribute('_text'))
-    s.addAspect('id', IdAttribute())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['ZopePageTemplate'] = s  # abbreviated. :-)
-
-    # file serializer
-    s = ObjectSerializer('OFS.Image', 'File')
-    s.addAspect('id', IdAttribute())
-    s.addAspect('data', FilePData())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['OFS.Image.File'] = s
-
-    # image serializer
-    s = ObjectSerializer('OFS.Image', 'Image')
-    s.addAspect('id', IdAttribute())
-    s.addAspect('data', FilePData())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['OFS.Image.Image'] = s
-
-    # anyfolder serializer
-    s = AnyObjectSerializer()
-    s.addAspect('items', FolderItems())
-    s.addAspect('id', IdAttribute())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['anyfolder'] = s
-
-    # anyfile serializer
-    s = AnyObjectSerializer()
-    s.addAspect('id', IdAttribute())
-    s.addAspect('data', RemainingState())
-    object_serializers['anyfile'] = s
-
-    # application serializer
-    s = ObjectSerializer('OFS.Application', 'Application')
-    s.addAspect('items', FolderItems())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['OFS.Application.Application'] = s
-
-    # root serializer
-    s = ObjectSerializer('Persistence', 'PersistentMapping')
-    aspect = FixedPersistentMapping()
-    aspect.add('Application', ('/',), ('OFS.Application.Application',))
-    s.addAspect('items', aspect)
-    s.addAspect('roll_call', RollCall())
-    root_serializer = s
+def createMapper(basepath, volatile=1):
+    """Object mapper factory.
 
-    # GATEWAYS
+    Usage in database configuration file:
+    factory=Products.AdaptableStorage.Zope2FS.createMapper
+    """
+    conn = FSConnection(basepath)
+    root_mapper = createZope2Mapper('/', 0)
+    root_mapper.setVolatile(int(volatile))
+    root_mapper.getClassifier().setGateway(FSClassificationSection(conn))
+    root_mapper.setKeychainGenerator(PathKeychainGenerator())
 
     # folder gateway
     g = ObjectGateway()
-    g.addGateway('items', FSDirectoryItems(fs_conn))
+    g.addGateway('items', FSDirectoryItems(conn))
     g.addGateway('id', FSAutoId())
-    g.addGateway('remainder', FSSectionData(fs_conn, 'remainder'))
-    object_gateways['OFS.Folder.Folder'] = g
+    g.addGateway('remainder', FSSectionData(conn, 'remainder'))
+    root_mapper.getSubMapper('OFS.Folder.Folder').setGateway(g)
 
     # page template gateway
     g = ObjectGateway()
-    g.addGateway('text', FSFileData(fs_conn))
+    g.addGateway('text', FSFileData(conn))
     g.addGateway('id', FSAutoId())
-    g.addGateway('remainder', FSSectionData(fs_conn, 'remainder'))
-    object_gateways['ZopePageTemplate'] = g
+    g.addGateway('remainder', FSSectionData(conn, 'remainder'))
+    root_mapper.getSubMapper('ZopePageTemplate').setGateway(g)
 
     # file gateway
     g = ObjectGateway()
-    g.addGateway('data', FSFileData(fs_conn))
+    g.addGateway('data', FSFileData(conn))
     g.addGateway('id', FSAutoId())
-    g.addGateway('remainder', FSSectionData(fs_conn, 'remainder'))
-    object_gateways['OFS.Image.File'] = g
+    g.addGateway('remainder', FSSectionData(conn, 'remainder'))
+    root_mapper.getSubMapper('OFS.Image.File').setGateway(g)
 
     # image gateway is identical
-    object_gateways['OFS.Image.Image'] = g
+    root_mapper.getSubMapper('OFS.Image.Image').setGateway(g)
 
     # anyfolder object gateway
     g = ObjectGateway()
-    g.addGateway('items', FSDirectoryItems(fs_conn))
+    g.addGateway('items', FSDirectoryItems(conn))
     g.addGateway('id', FSAutoId())
-    g.addGateway('remainder', FSSectionData(fs_conn, 'remainder'))
-    object_gateways['anyfolder'] = g
+    g.addGateway('remainder', FSSectionData(conn, 'remainder'))
+    root_mapper.getSubMapper('anyfolder').setGateway(g)
 
     # anyfile object gateway
     g = ObjectGateway()
     g.addGateway('id', FSAutoId())
-    g.addGateway('data', FSFileData(fs_conn))
-    object_gateways['anyfile'] = g
+    g.addGateway('remainder', FSFileData(conn))
+    root_mapper.getSubMapper('anyfile').setGateway(g)
 
     # application gateway
     g = ObjectGateway()
-    g.addGateway('items', FSDirectoryItems(fs_conn))
-    g.addGateway('remainder', FSSectionData(fs_conn, 'remainder'))
-    object_gateways['OFS.Application.Application'] = g
-
-    # root gateway (no storage)
-    g = ObjectGateway()
-    root_gateway = g
-
-    # Sanity check
-    s_keys = object_serializers.keys()
-    s_keys.sort()
-    g_keys = object_gateways.keys()
-    g_keys.sort()
-    assert s_keys == g_keys
-
-    # Put everything together
-    classifier = MetaTypeClassifier(FSClassificationSection(fs_conn))
-    classifier.registerDefaultLoader('Folder', 'OFS.Folder.Folder', 1)
-    classifier.registerDefaultLoader('File', 'OFS.Image.File', 0)
-    classifier.registerDefaultStorage('(folderish object)', 'anyfolder', 1)
-    classifier.registerDefaultStorage('(fileish object)', 'anyfile', 0)
-    classifier.registerKey('Application', 'OFS.Application.Application', '/')
-    classifier.register('CMF Skins Tool', 'anyfile')  # XXX workaround
-
-    classifier.register('Page Template', 'ZopePageTemplate', (
-        '.pt', '.zpt', '.html'))
-    classifier.register('Image', 'OFS.Image.Image', (
-        '.gif', '.jpg', '.jpeg', '.png'))
-
-    keychain_gen = PathKeychainGenerator()
-    rm = ObjectMapper(
-        None, root_serializer, root_gateway, classifier, keychain_gen)
-    for name in s_keys:
-        mapper = ObjectMapper(rm, object_serializers[name],
-                              object_gateways[name], volatile=volatile)
-        rm.addSubMapper(name, mapper)
-
-    return rm, fs_conn
-
-
-# For use in dbtab.conf:
-
-from zodb.public import ASConnection, ASStorage, ASDB, StaticResource
-
-
-class Zope2FSStorage (ASStorage):
-
-    def __init__(self, basepath, volatile=0, **kw):
-        dm, fs_conn = createMapper(basepath, int(volatile))
-        res = StaticResource(dm)
-        ASStorage.__init__(self, res, [fs_conn], **kw)
-
+    g.addGateway('items', FSDirectoryItems(conn))
+    g.addGateway('remainder', FSSectionData(conn, 'remainder'))
+    root_mapper.getSubMapper('OFS.Application.Application').setGateway(g)
 
-class Zope2FSDatabase (ASDB):
+    root_mapper.checkConfiguration()
 
-    def __init__(self, storage, **kw):
-        ASDB.__init__(self, storage, storage._mapper_resource, **kw)
+    return root_mapper, [conn]
 


=== Products/AdaptableStorage/Zope2SQL.py 1.4 => 1.5 ===
--- Products/AdaptableStorage/Zope2SQL.py:1.4	Fri Dec 13 15:42:02 2002
+++ Products/AdaptableStorage/Zope2SQL.py	Mon Dec 23 23:29:30 2002
@@ -17,139 +17,89 @@
 """
 
 
-from serial.public \
-     import ObjectSerializer, ObjectGateway, ObjectMapper
-from serial_std.public \
-     import RollCall, FixedPersistentMapping, IgnoredAttribute, \
-     PathKeychainGenerator, AnyObjectSerializer
-from serial_ofs.public import FolderItemsByKeychain, MetaTypeClassifier, \
-     IdAttribute
+from serial.public import ObjectGateway
 from gateway_sql.public import PsycopgConnection, SQLClassification, \
-     SQLFolderItems, SQLItemId, SQLKeychainGenerator, SQLRemainder
-from zodb.public import RemainingState
+     SQLFolderItems, SQLItemId, SQLKeychainGenerator, SQLObjectData, \
+     SQLRemainder
 
+from Zope2Mapper import createZope2Mapper
 
-def createMapper(params='', table_prefix='zodb', volatile=1):
-    conn = PsycopgConnection(params, table_prefix)
-
-    object_serializers = {}
-    object_gateways = {}
-
-    # SERIALIZERS
 
-    # folder serializer
-    s = ObjectSerializer('OFS.Folder', 'Folder')
-    s.addAspect('items', FolderItemsByKeychain())
-    s.addAspect('id', IdAttribute())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['OFS.Folder.Folder'] = s
-
-    # anyfolder serializer
-    s = AnyObjectSerializer()
-    s.addAspect('items', FolderItemsByKeychain())
-    s.addAspect('id', IdAttribute())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['anyfolder'] = s
-
-    # anyfile serializer
-    s = AnyObjectSerializer()
-    s.addAspect('id', IdAttribute())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['anyfile'] = s
-
-    # application serializer
-    s = ObjectSerializer('OFS.Application', 'Application')
-    s.addAspect('items', FolderItemsByKeychain())
-    s.addAspect('remainder', RemainingState())
-    object_serializers['OFS.Application.Application'] = s
-
-    # root serializer
-    s = ObjectSerializer('Persistence', 'PersistentMapping')
-    aspect = FixedPersistentMapping()
-    aspect.add('Application', (0,), ('OFS.Application.Application',))
-    s.addAspect('items', aspect)
-    s.addAspect('roll_call', RollCall())
-    root_serializer = s
-
-    # GATEWAYS
+def createMapperPlus(params='', table_prefix='zodb', volatile=1):
+    """Object mapper factory, with extra return arg for testing purposes
+    """
+    conn = PsycopgConnection(params, table_prefix)
+    root_mapper = createZope2Mapper(0, 1)
+    root_mapper.setVolatile(int(volatile))
+    root_mapper.getClassifier().setGateway(SQLClassification(conn))
+    root_mapper.setKeychainGenerator(SQLKeychainGenerator(conn))
 
     folder_items_gw = SQLFolderItems(conn)
     item_id_gw = SQLItemId(conn)
     remainder_gw = SQLRemainder(conn)
     classification_gw = SQLClassification(conn)
+    file_data_gw = SQLObjectData(conn)
     keychain_gen = SQLKeychainGenerator(conn)
-    gws = (folder_items_gw, item_id_gw, remainder_gw, classification_gw,
-           keychain_gen)
+    gws = (
+        folder_items_gw,
+        item_id_gw,
+        remainder_gw,
+        file_data_gw,
+        classification_gw,
+        keychain_gen,
+        )
 
     # folder gateway
     g = ObjectGateway()
     g.addGateway('items', folder_items_gw)
     g.addGateway('id', item_id_gw)
     g.addGateway('remainder', remainder_gw)
-    object_gateways['OFS.Folder.Folder'] = g
+    root_mapper.getSubMapper('OFS.Folder.Folder').setGateway(g)
+
+    # page template gateway
+    g = ObjectGateway()
+    g.addGateway('text', file_data_gw)
+    g.addGateway('id', item_id_gw)
+    g.addGateway('remainder', remainder_gw)
+    root_mapper.getSubMapper('ZopePageTemplate').setGateway(g)
+
+    # file gateway
+    g = ObjectGateway()
+    g.addGateway('data', file_data_gw)
+    g.addGateway('id', item_id_gw)
+    g.addGateway('remainder', remainder_gw)
+    root_mapper.getSubMapper('OFS.Image.File').setGateway(g)
+
+    # image gateway is identical
+    root_mapper.getSubMapper('OFS.Image.Image').setGateway(g)
 
     # anyfolder object gateway
     g = ObjectGateway()
     g.addGateway('items', folder_items_gw)
     g.addGateway('id', item_id_gw)
     g.addGateway('remainder', remainder_gw)
-    object_gateways['anyfolder'] = g
+    root_mapper.getSubMapper('anyfolder').setGateway(g)
 
     # anyfile object gateway
     g = ObjectGateway()
     g.addGateway('id', item_id_gw)
     g.addGateway('remainder', remainder_gw)
-    object_gateways['anyfile'] = g
+    root_mapper.getSubMapper('anyfile').setGateway(g)
 
     # application gateway
     g = ObjectGateway()
     g.addGateway('items', folder_items_gw)
     g.addGateway('remainder', remainder_gw)
-    object_gateways['OFS.Application.Application'] = g
-
-    # root gateway (no storage)
-    g = ObjectGateway()
-    root_gateway = g
-
-    # Sanity check
-    s_keys = object_serializers.keys()
-    s_keys.sort()
-    g_keys = object_gateways.keys()
-    g_keys.sort()
-    assert s_keys == g_keys
-
-    # Put everything together
-    classifier = MetaTypeClassifier(classification_gw)
-    classifier.registerDefaultLoader('Folder', 'OFS.Folder.Folder', 1)
-    classifier.registerDefaultStorage('(folderish object)', 'anyfolder', 1)
-    classifier.registerDefaultStorage('(fileish object)', 'anyfile', 0)
-    classifier.registerKey('Application', 'OFS.Application.Application', 0)
-    classifier.register('CMF Skins Tool', 'anyfile')  # XXX workaround
-    rm = ObjectMapper(
-        None, root_serializer, root_gateway, classifier, keychain_gen)
-    for name in s_keys:
-        mapper = ObjectMapper(rm, object_serializers[name],
-                              object_gateways[name], volatile=volatile)
-        rm.addSubMapper(name, mapper)
-
-    return rm, conn, gws
+    root_mapper.getSubMapper('OFS.Application.Application').setGateway(g)
 
+    return root_mapper, [conn], gws
 
-# For use in dbtab.conf:
 
-from zodb.public import ASConnection, ASStorage, ASDB, StaticResource
-
-
-class Zope2SQLStorage (ASStorage):
-
-    def __init__(self, params='', table_prefix='zodb', volatile=1, **kw):
-        dm, conn, gws = createMapper(params, table_prefix, int(volatile))
-        res = StaticResource(dm)
-        ASStorage.__init__(self, res, [conn], **kw)
-
-
-class Zope2SQLDatabase (ASDB):
+def createMapper(params='', table_prefix='zodb', volatile=1):
+    """Object mapper factory.
 
-    def __init__(self, storage, **kw):
-        ASDB.__init__(self, storage, storage._mapper_resource, **kw)
+    Usage in database configuration file:
+    factory=Products.AdaptableStorage.Zope2SQL.createMapper
+    """
+    return createMapperPlus(params, table_prefix, volatile)[:2]
 


=== Products/AdaptableStorage/__init__.py 1.5 => 1.6 ===
--- Products/AdaptableStorage/__init__.py:1.5	Tue Dec  3 18:10:52 2002
+++ Products/AdaptableStorage/__init__.py	Mon Dec 23 23:29:30 2002
@@ -26,3 +26,4 @@
     from patches import applyPatches
     applyPatches()
 
+import StorageTypesConfiguration