[Zope-CVS] CVS: Products/Ape/lib/apelib/zope2 - __init__.py:1.1 basemapper.py:1.1 classifier.py:1.1 fsmapper.py:1.1 ofsserial.py:1.1 scripts.py:1.1 security.py:1.1 sqlmapper.py:1.1

Shane Hathaway shane@zope.com
Wed, 9 Apr 2003 23:10:00 -0400


Update of /cvs-repository/Products/Ape/lib/apelib/zope2
In directory cvs.zope.org:/tmp/cvs-serv32010/lib/apelib/zope2

Added Files:
	__init__.py basemapper.py classifier.py fsmapper.py 
	ofsserial.py scripts.py security.py sqlmapper.py 
Log Message:
Moved apelib into a "lib" subdirectory.  This simplified the
Python hacking required to make apelib a top-level package.  Sorry
about the flood of checkins, but CVS makes a move like this quite painful.


=== Added File Products/Ape/lib/apelib/zope2/__init__.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.
#
##############################################################################
"""Zope 2 support.

$Id: __init__.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""



=== Added File Products/Ape/lib/apelib/zope2/basemapper.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.
#
##############################################################################
"""Zope 2 apelib mappers.

$Id: basemapper.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""

from apelib.core import gateways, mapper, serializers
from apelib.zodb3 import serializers as zodb3serializers
from apelib.zope2 import classifier, ofsserial, scripts, security


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 = mapper.Mapper()
    cfr = classifier.MetaTypeClassifier()
    root_mapper.setClassifier(cfr)
    cs = serializers.CompositeSerializer('Persistence', 'PersistentMapping')
    serializer = zodb3serializers.FixedPersistentMapping()
    serializer.add('Application', (app_key,), ('OFS.Application.Application',))
    cs.addSerializer('items', serializer)
    cs.addSerializer('roll_call', zodb3serializers.RollCall())
    root_mapper.setSerializer(cs)
    root_mapper.setGateway(gateways.CompositeGateway())  # No storage necessary

    # Prepare some common names
    if stored_keychains:
        folder_items_serializer = ofsserial.FolderItemsByKeychain()
    else:
        folder_items_serializer = ofsserial.FolderItems()

    # abstract base mapper
    m = root_mapper.addSubMapper('base')
    cs = serializers.CompositeSerializer(None, None)
    m.setSerializer(cs)
    cs.addSerializer('id', ofsserial.IdAttribute())
    cs.addSerializer('modtime', zodb3serializers.ModTimeAttribute())
    cs.addSerializer('security', security.SecurityAttributes())
    cs.addSerializer('remainder', zodb3serializers.RemainingState(), final=1)
    base = cs

    # abstract mapper with properties
    m = root_mapper.addSubMapper('base_p')
    cs = serializers.CompositeSerializer(None, None, base)
    m.setSerializer(cs)
    cs.addSerializer('properties', ofsserial.OFSProperties())
    base_p = cs

    # folder mapper
    m = root_mapper.addSubMapper('OFS.Folder.Folder')
    cs = serializers.CompositeSerializer('OFS.Folder', 'Folder', base_p)
    m.setSerializer(cs)
    cs.addSerializer('items', folder_items_serializer)
    cfr.registerDefaultLoader('Folder', 'OFS.Folder.Folder', 1)

    # file mapper
    m = root_mapper.addSubMapper('OFS.Image.File')
    cs = serializers.CompositeSerializer('OFS.Image', 'File', base_p)
    m.setSerializer(cs)
    cs.addSerializer('data', ofsserial.FilePData())
    cfr.registerDefaultLoader('File', 'OFS.Image.File', 0)
    cfr.setFlags('OFS.Image.File', cfr.CONTENT_TYPE_ATTR)

    # image mapper
    m = root_mapper.addSubMapper('OFS.Image.Image')
    cs = serializers.CompositeSerializer('OFS.Image', 'Image', base_p)
    m.setSerializer(cs)
    cs.addSerializer('data', ofsserial.FilePData())
    cfr.register('Image', 'OFS.Image.Image', (
        '.gif', '.jpg', '.jpeg', '.png'))
    cfr.setFlags('OFS.Image.Image', cfr.CONTENT_TYPE_ATTR)

    # page template mapper
    m = root_mapper.addSubMapper('ZopePageTemplate')  # abbreviated name
    cs = serializers.CompositeSerializer(
        'Products.PageTemplates.ZopePageTemplate', 'ZopePageTemplate', base_p)
    m.setSerializer(cs)
    cs.addSerializer('text', serializers.StringDataAttribute('_text'))
    cfr.register('Page Template', 'ZopePageTemplate', (
        '.html', '.htm', '.zpt', '.pt'))

    # dtml method mapper
    m = root_mapper.addSubMapper('OFS.DTMLMethod.DTMLMethod')
    cs = serializers.CompositeSerializer('OFS.DTMLMethod', 'DTMLMethod', base)
    m.setSerializer(cs)
    cs.addSerializer('text', serializers.StringDataAttribute('raw'))
    cfr.register('DTML Method', 'OFS.DTMLMethod.DTMLMethod', ('.dtml',))

    # dtml document mapper
    m = root_mapper.addSubMapper('OFS.DTMLDocument.DTMLDocument')
    cs = serializers.CompositeSerializer(
        'OFS.DTMLDocument', 'DTMLDocument', base_p)
    m.setSerializer(cs)
    cs.addSerializer('text', serializers.StringDataAttribute('raw'))
    cfr.register('DTML Document', 'OFS.DTMLDocument.DTMLDocument')
      
    # zsql mapper
    m = root_mapper.addSubMapper('Products.ZSQLMethods.SQL.SQL')
    cs = serializers.CompositeSerializer(
        'Products.ZSQLMethods.SQL', 'SQL', base)
    m.setSerializer(cs)
    cs.addSerializer('properties',
                     scripts.ZSQLMethodPropertiesSerializer(), 1)
    cs.addSerializer('text', scripts.ZSQLMethodSerializer())
    cfr.register('Z SQL Method', 'Products.ZSQLMethods.SQL.SQL', (
        '.sql', ))
      
    # python script mapper
    m = root_mapper.addSubMapper('PythonScript') # abbreviated name
    cs = serializers.CompositeSerializer(
        'Products.PythonScripts.PythonScript', 'PythonScript', base)
    m.setSerializer(cs)
    cs.addSerializer('body', scripts.PythonScriptSerializer())
    cfr.register('Script (Python)', 'PythonScript', ('.py', ))

    # user folder mapper
    m = root_mapper.addSubMapper('AccessControl.User.UserFolder')
    cs = serializers.CompositeSerializer(
        'AccessControl.User', 'UserFolder', base)
    m.setSerializer(cs)
    cs.addSerializer('data', security.UserFolderSerializer())
    cfr.register('User Folder', 'AccessControl.User.UserFolder')

    # anyfolder mapper
    m = root_mapper.addSubMapper('anyfolder')
    cs = serializers.AnyObjectSerializer(base)
    m.setSerializer(cs)
    cs.addSerializer('properties', serializers.OptionalSerializer(
        ofsserial.OFSProperties(), []), 1)
    cs.addSerializer('items', folder_items_serializer)
    cfr.registerDefaultStorage('(folderish object)', 'anyfolder', 1)

    # anyfile mapper
    m = root_mapper.addSubMapper('anyfile')
    cs = serializers.AnyObjectSerializer(base)
    m.setSerializer(cs)
    cs.addSerializer('properties', serializers.OptionalSerializer(
        ofsserial.OFSProperties(), []), 1)
    cfr.registerDefaultStorage('(fileish object)', 'anyfile', 0)

    # application mapper
    m = root_mapper.addSubMapper('OFS.Application.Application')
    cs = serializers.CompositeSerializer(
        'OFS.Application', 'Application', base_p)
    m.setSerializer(cs)
    cs.removeSerializer('id')
    cs.addSerializer('items', folder_items_serializer)
    cfr.registerKey(
        'Application', 'OFS.Application.Application', app_key)

    # Other stuff
    cfr.register('CMF Skins Tool', 'anyfile')  # XXX workaround
    cfr.register('Control Panel', 'anyfile')   # XXX workaround

    return root_mapper



=== Added File Products/Ape/lib/apelib/zope2/classifier.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Zope 2 meta_type based classification.

$Id: classifier.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""

from mimetypes import guess_extension

from Acquisition import aq_base
from OFS.ObjectManager import ObjectManager

from apelib.core.interfaces import IClassifier
from apelib.core.exceptions import DeserializationError

# guess_extension() is useful but it's unoptimized and sometimes
# chooses strange extensions.  fixed_extensions does nothing other than
# suggest a filename extension given a content type.  It contains
# some better defaults.
fixed_extensions = {
    'text/plain': '.txt',
    'text/html':  '.html',
    'image/png':  '.png',
    'image/jpg':  '.jpg',
    'image/jpeg': '.jpg',
    'image/gif':  '.gif',
    'application/octet-stream': '',  # No extension--too overloaded.
    }


class MetaTypeClassifier:
    """A classifier based on meta_type attributes.
    """
    __implements__ = IClassifier

    # flag values (constant)
    CONTENT_TYPE_ATTR = 1


    def __init__(self, gw=None):
        self.gw = gw
        self.key_to_res = {}
        self.ext_to_mt = {}
        self.mt_to_ext = {}
        self.fmt_to_mt = {}
        self.mt_to_mapper = {}
        self.flags = {}


    def setGateway(self, gw):
        self.gw = gw


    def register(self, meta_type, mapper_name, extensions=()):
        """Registers a mapper to handle a Zope meta_type."""
        for ext in extensions:
            if not ext.startswith('.'):
                ext = '.' + ext
            ext = ext.lower()
            self.ext_to_mt[ext] = meta_type
        if extensions:
            self.mt_to_ext[meta_type] = extensions[0]
        self.mt_to_mapper[meta_type] = mapper_name


    def registerKey(self, meta_type, mapper_name, key):
        """Registers a mapper to handle a specific path.

        For example, the application object mapper usually handles
        the path '/'.
        """
        self.key_to_res[key] = ({'meta_type': meta_type}, mapper_name)


    def registerDefaultLoader(self, meta_type, mapper_name, isdir):
        """Registers a mapper to load unknown files or directories."""
        if isdir:
            ext = '<directory>'
        else:
            ext = '<file>'
        self.ext_to_mt[ext] = meta_type
        self.mt_to_mapper[meta_type] = mapper_name


    def registerDefaultStorage(self, meta_type, mapper_name, folderish):
        """Registers a mapper to store unknown objects."""
        if folderish:
            fmt = 'folder'
        else:
            fmt = 'file'
        self.fmt_to_mt[fmt] = meta_type
        self.mt_to_mapper[meta_type] = mapper_name


    def setFlags(self, mapper_name, flags):
        """Sets flags associated with a certain mapper."""
        self.flags[mapper_name] = flags


    def classifyObject(self, value, keychain):
        """Chooses a mapper and classification for storing an object."""
        res = self.key_to_res.get(keychain[-1])
        if res is not None:
            return res
        mt = value.meta_type
        mapper_name = self.mt_to_mapper.get(mt)
        if mapper_name is None:
            folderish = isinstance(value, ObjectManager)
            # Store in a default format
            if folderish:
                fmt = 'folder'
            else:
                fmt = 'file'
            mt = self.fmt_to_mt.get(fmt)
            if mt is None:
                raise SerializationError(
                    'No classification known for %s' % repr(keychain))
            mapper_name = self.mt_to_mapper.get(mt)
            if mapper_name is None:
                raise DeserializationError(
                    'No mapper known for meta_type %s' % repr(mt))
        klass = value.__class__
        ci = '%s:%s' % (klass.__module__, klass.__name__)
        classification = {'meta_type': mt, 'class_name': ci}

        flags = self.flags.get(mapper_name, 0)
        if flags and (flags & MetaTypeClassifier.CONTENT_TYPE_ATTR):
            ct = str(getattr(aq_base(value), 'content_type', None))
            if ct:
                ext = fixed_extensions.get(ct)
                if ext is None:
                    ext = guess_extension(ct)
        else:
            ext = self.mt_to_ext.get(mt)
        if ext:
            classification['extension'] = ext

        return classification, mapper_name


    def classifyState(self, event):
        """Chooses a mapper and classification for loading an object."""
        keychain = event.getKeychain()
        res = self.key_to_res.get(keychain[-1])
        if res is not None:
            return res
        classification, serial = self.gw.load(event)
        mt = classification.get('meta_type')
        if mt is None:
            t = classification.get('node_type')
            if t == 'd':
                # Directory
                mt = self.ext_to_mt.get('<directory>', 'Folder')
            elif t == 'f':
                # File
                ext = classification.get('extension')
                if ext:
                    if not ext.startswith('.'):
                        ext = '.' + ext
                    mt = self.ext_to_mt.get(ext.lower())
                if not mt:
                    mt = self.ext_to_mt.get('<file>', 'File')
            else:
                raise DeserializationError(
                    'No classification known for %s' % repr(keychain))
            assert mt is not None
            classification['meta_type'] = mt
        mapper_name = self.mt_to_mapper.get(mt)
        if mapper_name is None:
            raise DeserializationError(
                'No mapper known for meta_type %s' % repr(mt))
        return classification, mapper_name


    def store(self, event, classification):
        """Stores the classification of an object."""
        return self.gw.store(event, classification)



=== Added File Products/Ape/lib/apelib/zope2/fsmapper.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 the filesystem.

$Id: fsmapper.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""

from apelib.core import gateways, keygen
from apelib.fs \
     import classification, connection, properties, security, structure
from apelib.zope2 import basemapper


def createMapper(basepath, volatile=1, **kw):
    """Object mapper factory.

    Usage in database configuration file:
    factory=apelib.zope2.fsmapper.createMapper
    """
    # The "volatile" argument is ignored.
    conn = connection.FSConnection(basepath, **kw)
    root_mapper = basemapper.createZope2Mapper('/', 0)
    root_mapper.getClassifier().setGateway(
        classification.FSClassificationSection(conn))
    root_mapper.setKeychainGenerator(keygen.PathKeychainGenerator())
    file_binary_data = structure.FSFileData(conn, text=0)
    file_text_data = structure.FSFileData(conn, text=1)

    # abstract base gateway
    g = gateways.CompositeGateway()
    g.addGateway('id', structure.FSAutoId())
    g.addGateway('modtime', structure.FSModTime(conn))
    g.addGateway('remainder', properties.FSSectionData(conn, 'remainder'))
    g.addGateway('security', security.FSSecurityAttributes(conn))
    root_mapper.getSubMapper('base').setGateway(g)
    base = g

    # abstract base gateway with properties
    g = gateways.CompositeGateway(base)
    g.addGateway('properties', properties.FSProperties(conn))
    root_mapper.getSubMapper('base_p').setGateway(g)
    base_p = g

    # folder gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('items', structure.FSDirectoryItems(conn))
    root_mapper.getSubMapper('OFS.Folder.Folder').setGateway(g)

    # page template gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('text', file_text_data)
    root_mapper.getSubMapper('ZopePageTemplate').setGateway(g)

    # dtml method gateway
    g = gateways.CompositeGateway(base)
    g.addGateway('text', file_text_data)
    root_mapper.getSubMapper('OFS.DTMLMethod.DTMLMethod').setGateway(g)
    
    # dtml document gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('text', file_text_data)
    root_mapper.getSubMapper('OFS.DTMLDocument.DTMLDocument').setGateway(g)

    # zsqlmethod mapper
    g = gateways.CompositeGateway(base)
    g.addGateway('text', file_text_data)
    g.addGateway('properties', properties.FSProperties(
        conn, 'ZSQL Properties'), 1)
    root_mapper.getSubMapper('Products.ZSQLMethods.SQL.SQL').setGateway(g)

    # python script mapper
    g = gateways.CompositeGateway(base)
    g.addGateway('body', file_text_data)
    root_mapper.getSubMapper('PythonScript').setGateway(g)

    # file gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('data', file_binary_data)
    root_mapper.getSubMapper('OFS.Image.File').setGateway(g)

    # image gateway is identical
    root_mapper.getSubMapper('OFS.Image.Image').setGateway(g)

    # user folder gateway
    g = gateways.CompositeGateway(base)
    g.addGateway('data', security.FSUserList(conn))
    root_mapper.getSubMapper('AccessControl.User.UserFolder').setGateway(g)

    # anyfolder object gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('items', structure.FSDirectoryItems(conn))
    root_mapper.getSubMapper('anyfolder').setGateway(g)

    # anyfile object gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('remainder', file_binary_data, 1)
    root_mapper.getSubMapper('anyfile').setGateway(g)

    # application gateway
    g = gateways.CompositeGateway(base_p)
    g.removeGateway('id')
    g.addGateway('items', structure.FSDirectoryItems(conn))
    root_mapper.getSubMapper('OFS.Application.Application').setGateway(g)

    root_mapper.checkConfiguration()

    return root_mapper, [conn]



=== Added File Products/Ape/lib/apelib/zope2/ofsserial.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Serializers for OFSP (object file system product) objects

$Id: ofsserial.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""

from cPickle import dumps, loads
from types import DictType, StringType

from Acquisition import aq_base
from OFS.SimpleItem import Item_w__name__
from OFS.ObjectManager import ObjectManager
from OFS.Image import File
from OFS.PropertyManager import PropertyManager

from apelib.core.interfaces import ISerializer
from apelib.core.schemas import FieldSchema, RowSequenceSchema
from apelib.core.exceptions import SerializationError

string_repr_types = {
    # Properties that are safe to render as strings for storage.
    # Other kinds of properties get pickled.
    'string': 1,
    'float': 1,
    'int': 1,
    'long': 1,
    'string': 1,
    'date': 1,
    'date_international': 1,
    'text': 1,
    'boolean': 1,
}


class FilePData:
    """Serializer of the 'data' attribute of OFS.File and OFS.Image"""

    __implements__ = ISerializer

    schema = FieldSchema('data', 'string')

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, File)

    def serialize(self, object, event):
        event.notifySerialized('data', object.data, 1)
        event.ignoreAttribute('size')
        event.ignoreAttribute('width')
        event.ignoreAttribute('height')
        return str(object.data)

    def deserialize(self, object, event, state):
        data, size = object._read_data(state)
        if not object.__dict__.get('content_type'):
            # Guess the content type.
            content_type = object._get_content_type(
                state, data, object.__name__)
        else:
            # The properties serializer is authoritative.  Defer to it.
            content_type = None
        object.update_data(data, content_type, size)
        event.notifyDeserialized('data', object.data)


class FolderItems:
    """Serializer for the items in an ObjectManager.

    This version does not store keychains, but instead assumes they
    can be computed."""

    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.addField('id', 'string', 1)

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, ObjectManager)

    def serialize(self, object, event):
        assert isinstance(object, ObjectManager), repr(object)
        state = []
        event.ignoreAttribute('_objects')
        mps = getattr(object, '_mount_points', None)
        for id, subob in object.objectItems():
            if mps and mps.has_key(id):
                # Store the mount point rather than the mounted object.
                subob = mps[id]
            base = aq_base(subob)
            keychain = event.identifyObject(base)
            expected = event.makeKeychain(id, 0)
            if keychain is not None and keychain != expected:
                raise SerializationError(
                    "Subobject %s has unexpected keychain, %s. Expected %s." %
                    (repr(base), repr(keychain), repr(expected)))
            keychain = expected
            event.notifySerializedRef(id, base, 1, keychain)
            state.append((id,))
        event.ignoreAttribute('_use_fixed_oids_')
        # Add a marker that tells the folder it has to move/rename
        # in a special way.  The _setOb patch sees this attribute.
        object._use_fixed_oids_ = 1
        return state

    def deserialize(self, object, event, state):
        assert isinstance(object, ObjectManager)
        object._use_fixed_oids_ = 1
        for (id,) in state:
            keychain = event.makeKeychain(id, 0)
            subob = event.dereference(id, keychain)
            setattr(object, id, subob)
            object._objects += ({'id': id, 'meta_type':
                                 subob.__class__.meta_type},)


class FolderItemsByKeychain:
    """ """
    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.addField('id', 'string', 1)
    schema.addField('keychain', 'keychain')

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, ObjectManager)

    def serialize(self, object, event):
        assert isinstance(object, ObjectManager), repr(object)
        state = []
        event.ignoreAttribute('_objects')
        mps = getattr(object, '_mount_points', None)
        for id, subob in object.objectItems():
            if mps and mps.has_key(id):
                # Store the mount point rather than the mounted object.
                subob = mps[id]
            base = aq_base(subob)
            keychain = event.identifyObject(base)
            if keychain is None:
                keychain = event.makeKeychain(id, 1)
            event.notifySerializedRef(id, base, 1, keychain)
            state.append((id, keychain))
        return state

    def deserialize(self, object, event, state):
        assert isinstance(object, ObjectManager)
        for (id, keychain) in state:
            subob = event.dereference(id, keychain)
            setattr(object, id, subob)
            object._objects += ({'id': id, 'meta_type':
                                 subob.__class__.meta_type},)



class IdAttribute:
    """Zope 2 id attribute."""

    __implements__ = ISerializer

    schema = FieldSchema('id', 'string')

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return 1

    def getAttrNameFor(self, object):
        if isinstance(object, Item_w__name__):
            return '__name__'
        else:
            return 'id'

    def serialize(self, object, event):
        attrname = self.getAttrNameFor(object)
        id = getattr(object, attrname)
        assert id, 'ID of %r is %r' % (object, id)
        event.notifySerialized(attrname, id, 1)
        return id

    def deserialize(self, object, event, state):
        attrname = self.getAttrNameFor(object)
        setattr(object, attrname, state)
        event.notifyDeserialized(attrname, state)



class OFSProperties:
    """Serializer for OFS.PropertyManager properties."""

    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.addField('id', 'string', 1)
    schema.addField('type', 'string')
    schema.addField('data', 'string')

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, PropertyManager)

    def serialize(self, object, event):
        res = []
        assert isinstance(object, PropertyManager), repr(object)
        assert object._properties is object._propertyMap()
        event.ignoreAttribute('_properties')
        for p in object._properties:
            name = p['id']
            t = p['type']
            event.ignoreAttribute(name)
            data = object.getProperty(name)
            if t == 'lines':
                v = '\n'.join(data)
            elif string_repr_types.get(t):
                v = str(data)
            else:
                # Pickle the value and any extra info about the property.
                # Extra info is present in select and multi-select properties.
                d = p.copy()
                del d['id']
                del d['type']
                if d.has_key('mode'):
                    del d['mode']
                d['value'] = data
                v = dumps(d)
            res.append((name, t, v))
        return res

    def deserialize(self, object, event, state):
        assert isinstance(object, PropertyManager)
        assert object._properties is object._propertyMap()
        if not state:
            # No stored properties.  Revert the object to its
            # class-defined property schema.
            if object.__dict__.has_key('_properties'):
                del object._properties
            return

        old_props = object.propdict()
        new_props = {}
        for id, t, v in state:
            p = old_props.get(id)
            if p is None:
                p = {'mode': 'wd'}
            else:
                p = p.copy()
            p['id'] = id
            p['type'] = t
            if v and not string_repr_types.get(t) and t != 'lines':
                # v is a pickle.
                # Check the pickle for extra property info.
                d = loads(v)
                if isinstance(d, DictType):
                    del d['value']
                    if d:
                        # The data is stored with extra property info.
                        p.update(d)
            new_props[id] = p

        if old_props != new_props:
            object._properties = tuple(new_props.values())

        for id, t, v in state:
            if t == 'lines':
                data = v.split('\n')
            elif string_repr_types.get(t):
                data = str(v)
            elif v:
                d = loads(v)
                if isinstance(d, DictType):
                    # The data is stored with extra property info.
                    data = d['value']
                else:
                    data = d
            else:
                # Fall back to a default.
                data = ''
            object._updateProperty(id, data)



=== Added File Products/Ape/lib/apelib/zope2/scripts.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Zope 2 script serialization

$Id: scripts.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""

import re
from types import StringType

from Products.PythonScripts.PythonScript import PythonScript
from Products.ZSQLMethods.SQL import SQL, SQLConnectionIDs
from Shared.DC.ZRDB.Aqueduct import parse
try:
    from IOBTree import Bucket
except ImportError:
    Bucket = lambda: {}

from apelib.core.interfaces import ISerializer
from apelib.core.schemas import FieldSchema, RowSequenceSchema


class PythonScriptSerializer:
    """Serializer for PythonScripts.

    PythonScriptSerializer serializes using the same representation
    as FTP or WebDAV.  All computable attributes like compiled code
    are dropped.
    """

    __implements__ = ISerializer

    schema = FieldSchema('data', 'string')

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, PythonScript)

    def serialize(self, object, event):
        assert isinstance(object, PythonScript)
        data = object.read()
        assert isinstance(data, StringType)
        event.ignoreAttributes((
            'title', '_params', '_body', '_bind_names',
            'warnings', 'errors', '_code', 'Python_magic', 
            'Script_magic', 'func_defaults', 'func_code', 
            'co_varnames', 'co_argcount',
            ))
        return data

    def deserialize(self, object, event, state):
        assert isinstance(state, StringType)
        assert isinstance(object, PythonScript)
        object.write(state) 
        object._makeFunction()



class ZSQLMethodSerializer:
    """Serializer for ZSQLMethods.

    ZSQLMethodSerializer serializes using the same representation
    as FTP or WebDAV.  All computable attributes like compiled code
    are dropped.
    """

    __implements__ = ISerializer

    schema = FieldSchema('data', 'string')

    params_re = re.compile(r'\s*<params>(.*)</params>\s*\n', re.I | re.S)

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, SQL)

    def serialize(self, object, event):
        data = object.document_src()
        event.ignoreAttributes(('_arg', 'template', 'arguments_src', 'src'))
        return data

    def deserialize(self, object, event, state):
        assert isinstance(state, StringType)
        assert isinstance(object, SQL)
        body = state
        m = self.params_re.match(body)
        if m:
            object.arguments_src = m.group(1)
            body = body[m.end():]
        else:
            object.arguments_src = ''
        object._arg = parse(object.arguments_src)
        object.src = body
        object.template = object.template_class(body)
        object.template.cook()
        object._v_cache = ({}, Bucket())
        if not hasattr(object, 'connection_id'):
            object.connection_id = ''


class ZSQLMethodPropertiesSerializer:
    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.addField('id', 'string', 1)
    schema.addField('type', 'string')
    schema.addField('data', 'string')

    attributes = {
        'title': str,
        'connection_id': str,
        'max_rows_': int,
        'max_cache_': int,
        'cache_time': int, 
        'class_name_': str, 
        'class_file_': str,
        'zclass': str, # XXX, what's that 
        'allow_simple_one_argument_traversal': int,
        'connection_hook': str, 
    }

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, SQL)

    def serialize(self, object, event):
        assert isinstance(object, SQL)
        res = []
        for attribute, factory in self.attributes.items():
            if not hasattr(object, attribute):
                continue
            value = getattr(object, attribute)
            t = factory.__name__
            if value is None:
                if factory in (int, long):
                    value = 0
                else: 
                    value = ''
            value = str(value)
            event.notifySerialized(attribute, value, 1)
            res.append((attribute, t, value))
        event.ignoreAttribute('_col') 
        return res 

    def deserialize(self, object, event, state):
        assert isinstance(object, SQL)
        for attribute, t, value in state:
            factory = self.attributes.get(attribute)
            if factory is None:
                continue
            value = factory(value)
            setattr(object, attribute, value)
            event.notifyDeserialized(attribute, value)
        if not hasattr(object, 'connection_id'):
            object.connection_id = ''



=== Added File Products/Ape/lib/apelib/zope2/security.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Zope 2 security information serializers.

$Id: security.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""

from types import TupleType

from Persistence import PersistentMapping
from AccessControl.User import User, UserFolder
from AccessControl.Permission import pname
import Products

from apelib.core.interfaces import ISerializer
from apelib.core.schemas import RowSequenceSchema


_permission_dict_cache = None

def getPermissionDict():
    """Returns a dictionary mapping permission attribute name to permission.

    Does not discover permissions defined in ZClass products, since that
    would require access to the Zope application in the database.
    """
    global _permission_dict_cache
    if _permission_dict_cache is not None:
        return _permission_dict_cache
    res = {}
    for item in Products.__ac_permissions__:
        p = item[0]
        attr = pname(p)
        res[attr] = p
    _permission_dict_cache = res
    return res


## Declaration types:
##
## executable owner
##   "executable-owner", "", "", path/to/userfolder/username
## local roles
##   "local-role", role_name, "", username
## user-defined roles
##   "define-role", role_name, "", ""
## proxy roles
##   "proxy-role", role_name, "", ""
## permission mapping
##   "permission-role", role_name, permission_name, ""
##   "permission-no-acquire", "", permission_name, ""


STANDARD_ROLES = {
    'Anonymous': 1,
    'Authenticated': 1,
    'Manager': 1,
    'Owner': 1,
    }


class SecurityAttributes:
    """Zope 2 security attribute serializer."""

    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.addField('declaration_type', 'string')
    schema.addField('role', 'string')
    schema.addField('permission', 'string')
    schema.addField('username', 'string')

    def getSchema(self):
        return self.schema

    def canSerialize(self, obj):
        return 1

    def serialize(self, obj, event):
        res = []

        eo = getattr(obj, '_owner', None)
        if eo is not None:
            event.ignoreAttribute('_owner')
            path, username = eo
            if '/' in username:
                raise ValueError, '/ not allowed in user names'
            s = '%s/%s' % ('/'.join(path), username)
            res.append(('executable-owner', '', '', s))

        roles = getattr(obj, '__ac_roles__', None)
        if roles is not None:
            event.ignoreAttribute('__ac_roles__')
            for role in roles:
                if not STANDARD_ROLES.has_key(role):
                    res.append(('define-role', role, '', ''))

        local_roles = getattr(obj, '__ac_local_roles__', None)
        if local_roles is not None:
            event.ignoreAttribute('__ac_local_roles__')
            for username, roles in local_roles.items():
                for role in roles:
                    res.append(('local-role', role, '', username))

        proxy_roles = getattr(obj, '_proxy_roles', None)
        if proxy_roles is not None:
            event.ignoreAttribute('_proxy_roles')
            for role in proxy_roles:
                res.append(('proxy-role', role, '', ''))

        p_dict = None
        for attr, value in obj.__dict__.items():
            if attr.endswith('_Permission') and attr.startswith('_'):
                if p_dict is None:
                    p_dict = getPermissionDict()
                p = p_dict.get(attr)
                if p is not None:
                    event.ignoreAttribute(attr)
                    for role in value:
                        res.append(('permission-role', role, p, ''))
                    # List means acquired, tuple means not acquired.
                    if isinstance(role, TupleType):
                        res.append(('permission-no-acquire', '', p, ''))

        return res
        

    def deserialize(self, obj, event, state):
        local_roles = {}       # { username -> [role,] }
        defined_roles = []     # [role,]
        proxy_roles = []       # [role,]
        permission_roles = {}  # { permission -> [role,] }
        permission_acquired = {}  # { permission -> 0 or 1 }

        for decl_type, role, permission, username in state:
            if decl_type == 'executable-owner':
                assert not role
                assert not permission
                assert username
                pos = username.rfind('/')
                if pos < 0:
                    # Default to the root folder
                    ufolder = ['acl_users']
                    uname = username
                else:
                    ufolder = list(username[:pos].split('/'))
                    uname = username[pos + 1:]
                assert ufolder
                assert uname
                obj._owner = (ufolder, uname)

            elif decl_type == 'local-role':
                assert role
                assert not permission
                assert username
                r = local_roles.get(username)
                if r is None:
                    r = []
                    local_roles[username] = r
                r.append(role)

            elif decl_type == 'define-role':
                assert role
                assert not permission
                assert not username
                defined_roles.append(role)

            elif decl_type == 'proxy-role':
                assert role
                assert not permission
                assert not username
                proxy_roles.append(role)

            elif decl_type == 'permission-role':
                assert role
                assert permission
                assert not username
                r = permission_roles.get(permission)
                if r is None:
                    r = []
                    permission_roles[permission] = r
                r.append(role)
                if not permission_acquired.has_key(permission):
                    permission_acquired[permission] = 1

            elif decl_type == 'permission-no-acquire':
                assert not role
                assert permission
                assert not username
                permission_acquired[permission] = 0

            else:
                raise ValueError, (
                    'declaration_type %s unknown' % repr(decl_type))

        if local_roles:
            obj.__ac_local_roles__ = local_roles
        if defined_roles:
            obj.__ac_roles__ = defined_roles
        if proxy_roles:
            obj._proxy_roles = proxy_roles
        
        for p, acquired in permission_acquired.items():
            roles = permission_roles.get(p)
            if not acquired:
                roles = tuple(roles)
            setattr(obj, pname(p), roles)



class UserFolderSerializer:
    """Serializer for a user folder.

    This version lets the application keep a list of all users in RAM.
    """

    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.addField('id', 'string', 1)
    schema.addField('password', 'string')
    schema.addField('roles', 'string:list')
    schema.addField('domains', 'string:list')

    def getSchema(self):
        return self.schema

    def canSerialize(self, object):
        return isinstance(object, UserFolder)

    def serialize(self, object, event):
        assert isinstance(object, UserFolder), repr(object)
        state = []
        event.ignoreAttribute('data')
        for id, user in object.data.items():
            assert isinstance(user, User), repr(user)
            assert len(user.__dict__.keys()) == 4, user.__dict__.keys()
            state.append((id, user.__,
                          tuple(user.roles), tuple(user.domains)))
            event.notifySerialized(id, user, 0)
        event.addUnmanagedPersistentObjects([object.data])
        event.addUnmanagedPersistentObjects(object.data.values())
        return state

    def deserialize(self, object, event, state):
        assert isinstance(object, UserFolder)
        object.data = PersistentMapping()
        for id, password, roles, domains in state:
            user = User(id, password, roles, domains)
            object.data[id] = user
            event.notifyDeserialized(id, user)
        event.addUnmanagedPersistentObjects([object.data])
        event.addUnmanagedPersistentObjects(object.data.values())



=== Added File Products/Ape/lib/apelib/zope2/sqlmapper.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 a Postgres database.

$Id: sqlmapper.py,v 1.1 2003/04/10 03:09:58 shane Exp $
"""

from apelib.core import gateways
from apelib.sql import classification, keygen, properties, security, structure
from apelib.zope2 import basemapper


def createSQLMapper(conn):
    """Object mapper factory, with extra return arg for testing purposes
    """
    root_mapper = basemapper.createZope2Mapper(0, 1)
    root_mapper.setKeychainGenerator(keygen.SQLKeychainGenerator(conn))

    folder_items_gw = structure.SQLFolderItems(conn)
    item_id_gw = structure.SQLItemId(conn)
    remainder_gw = structure.SQLRemainder(conn)
    file_data_gw = structure.SQLObjectData(conn)
    modtime_gw = structure.SQLModTime(conn)
    properties_gw = properties.SQLProperties(conn)
    security_gw = security.SQLSecurityAttributes(conn)
    userlist_gw = security.SQLUserList(conn)
    classification_gw = classification.SQLClassification(conn)
    keychain_gen = keygen.SQLKeychainGenerator(conn)
    gws = (
        folder_items_gw,
        remainder_gw,
        item_id_gw,
        file_data_gw,
        modtime_gw,
        properties_gw,
        security_gw,
        userlist_gw,
        classification_gw,
        keychain_gen,
        )

    root_mapper.getClassifier().setGateway(classification_gw)

    # abstract base gateway
    g = gateways.CompositeGateway()
    g.addGateway('id', item_id_gw)
    g.addGateway('modtime', modtime_gw)
    g.addGateway('remainder', remainder_gw)
    g.addGateway('security', security_gw)
    root_mapper.getSubMapper('base').setGateway(g)
    base = g

    # abstract base gateway with properties
    g = gateways.CompositeGateway(base)
    g.addGateway('properties', properties_gw)
    root_mapper.getSubMapper('base_p').setGateway(g)
    base_p = g

    # folder gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('items', folder_items_gw)
    root_mapper.getSubMapper('OFS.Folder.Folder').setGateway(g)

    # page template gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('text', file_data_gw)
    root_mapper.getSubMapper('ZopePageTemplate').setGateway(g)

    # dtml method gateway
    g = gateways.CompositeGateway(base)
    g.addGateway('text', file_data_gw)
    root_mapper.getSubMapper('OFS.DTMLMethod.DTMLMethod').setGateway(g)
    
    # dtml document gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('text', file_data_gw)
    root_mapper.getSubMapper('OFS.DTMLDocument.DTMLDocument').setGateway(g)

    # zsqlmethod mapper
    g = gateways.CompositeGateway(base_p)
    g.addGateway('text', file_data_gw)
    root_mapper.getSubMapper('Products.ZSQLMethods.SQL.SQL').setGateway(g)

    # python script mapper
    g = gateways.CompositeGateway(base)
    g.addGateway('body', file_data_gw)
    root_mapper.getSubMapper('PythonScript').setGateway(g)

    # file gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('data', file_data_gw)
    root_mapper.getSubMapper('OFS.Image.File').setGateway(g)

    # image gateway is identical
    root_mapper.getSubMapper('OFS.Image.Image').setGateway(g)

    # user folder gateway
    g = gateways.CompositeGateway(base)
    g.addGateway('data', userlist_gw)
    root_mapper.getSubMapper('AccessControl.User.UserFolder').setGateway(g)

    # anyfolder object gateway
    g = gateways.CompositeGateway(base_p)
    g.addGateway('items', folder_items_gw)
    root_mapper.getSubMapper('anyfolder').setGateway(g)

    # anyfile object gateway
    g = gateways.CompositeGateway(base_p)
    root_mapper.getSubMapper('anyfile').setGateway(g)

    # application gateway
    g = gateways.CompositeGateway(base_p)
    g.removeGateway('id')
    g.addGateway('items', folder_items_gw)
    root_mapper.getSubMapper('OFS.Application.Application').setGateway(g)

    root_mapper.checkConfiguration()

    return root_mapper, [conn], gws


def createPostgreSQLMapper(params='', table_prefix='zodb', volatile=1):
    """Object mapper factory.

    Usage in database configuration file:
    factory=apelib.zope2.fsmapper.createMapper
    """
    # The "volatile" argument is ignored.
    from apelib.sql import pg
    conn = pg.PsycopgConnection(params, table_prefix)
    return createSQLMapper(conn)[:2]