[Zope-CVS] CVS: Products/Ape/doc - apexml.txt:1.3 outline.txt:1.3
Shane Hathaway
shane at zope.com
Mon Mar 15 23:56:42 EST 2004
Update of /cvs-repository/Products/Ape/doc
In directory cvs.zope.org:/tmp/cvs-serv23343
Modified Files:
apexml.txt outline.txt
Log Message:
Updated the documentation to reflect recent changes.
- Methods renamed
- No more domain mappers
- Slightly simpler XML
- Use of composite serializers / gateways is now optional
The documentation is supplemented by interfaces and docstrings.
=== Products/Ape/doc/apexml.txt 1.2 => 1.3 ===
--- Products/Ape/doc/apexml.txt:1.2 Wed Jul 30 17:32:53 2003
+++ Products/Ape/doc/apexml.txt Mon Mar 15 23:56:40 2004
@@ -82,7 +82,6 @@
<mapper
name="..."
[ class="..." ]
- [ parent="..." ]
[ extends="..." ] >
...
</mapper>
@@ -95,8 +94,6 @@
serializer
gateway
- classifier
- keygen
use-for
option
variation
@@ -126,17 +123,11 @@
does not need to specify a class.
The 'extends' attribute tells the mapper to inherit components
- from a base mapper. The mapper will inherit gateways,
- serializers, a classifier, and a keychain, but no options,
- attributes, or 'use-for' registrations. The derived mapper can
- override or disable inherited subcomponents by using the same name
- that inherited subcomponents use.
-
- The 'parent' attribute makes the mapper a child of another mapper.
- It should contain the name of a mapper. Ape ignores mappers that
- are not part of a mapper tree, so most mappers need a 'parent'
- attribute.
-
+ from a base mapper. The sub-mapper will inherit gateways and
+ serializers, but no options or 'use-for' registrations. The
+ derived mapper can override or disable inherited subcomponents by
+ using the same name that inherited subcomponents use.
+
Internally, Ape interprets a mapper element as several directives.
The directives get stored in small indexed tables. When an
application such as Zope requests a configured mapper, a
@@ -146,18 +137,15 @@
<serializer
- name="..."
factory="..." | use="..."
+ [ name="..." ]
[ enabled="..." ]
- [ param="..." ]
[ order="..." ] />
- Declares a serializer. The 'name' attribute is required. Either
- 'factory' or 'use' is required. The 'enabled', 'param', and
- 'order' attributes are optional. The 'param' attribute is valid
- only when a 'factory' is provided. The 'order' attribute is valid
- only when the element descends from a mapper element. This
- element accepts no child elements.
+ Declares a serializer. Either 'factory' or 'use' is required.
+ The 'name', 'enabled', and 'order' attributes are optional. The
+ 'order' attribute is valid only when the element descends from a
+ mapper element. This element accepts no child elements.
You can use this element to declare either a reusable serializer,
by placing it outside any mapper element, or a non-reusable
@@ -169,20 +157,24 @@
Use a Python class to implement a serializer, then use the
'factory' attribute to link your class into Ape. Specify a
fully-qualified class name, such as "mypackage.mymodule.myclass".
- If your class constructor requires a parameter, you may pass one
- string parameter using the 'param' attribute.
+ If your class constructor requires parameters, you may add them to
+ the end of the 'factory' attribute in parentheses. (Only
+ positional arguments are supported.)
To import a reusable serializer into a mapper, add a serializer
declaration to a 'mapper' element, specifying the name of the
serializer to import in the 'use' attribute of the serializer
declaration. The 'factory' and 'use' attributes can not be used
- together.
-
- Mappers can have any number of serializers, but keep the number
- small for speed. Sometimes the order in which the serializers get
- invoked matters. In those rare cases, use the 'order' attribute
- to specify a sort key. Use 'a' to make it run first and 'z' to
- make it run last. The default sort key is 'middle'.
+ together. If you don't specify a 'name' attribute, the serializer
+ will be used as the main serializer for the mapper. If you
+ specify a 'name' attribute, the serializer will be added to the
+ mapper's composite serializer.
+
+ Mappers can have any number of serializers. Sometimes the order
+ in which the serializers get called matters. In those rare cases,
+ use the 'order' attribute to specify a sort key. Use 'a' to make
+ it run first and 'z' to make it run last. The default sort key is
+ 'middle'.
The 'enabled' attribute lets you disable an unwanted inherited
serializer. To do this, set the 'enabled' attribute to 'false'
@@ -191,15 +183,13 @@
<gateway
- name="..."
factory="..." | use="..."
- [ enabled="..." ]
- [ param="..." ] />
+ [ name="..." ]
+ [ enabled="..." ] />
- Declares a gateway. The 'name' attribute is required. Either
- 'factory' or 'use' is required. The 'enabled' and 'param'
- attributes are optional. The 'param' attribute is valid only when
- a 'factory' is provided. This element accepts no child elements.
+ Declares a gateway. Either 'factory' or 'use' is required. The
+ 'name' and 'enabled' attributes are optional. This element
+ accepts no child elements.
You can use this element to declare either a reusable gateway, by
placing it outside any mapper element, or a non-reusable gateway,
@@ -210,8 +200,9 @@
Use a Python class to implement a gateway, then use the 'factory'
attribute to link your class into Ape. Specify a fully-qualified
class name, such as "mypackage.mymodule.myclass". If your class
- constructor requires a parameter, you may pass one string
- parameter using the 'param' attribute.
+ constructor requires parameters, you may add them to the end of
+ the 'factory' attribute in parentheses. (Only positional
+ arguments are supported.)
To import a reusable gateway into a mapper, add a gateway
declaration to a 'mapper' element, specifying the name of the
@@ -219,9 +210,8 @@
declaration. The 'factory' and 'use' attributes can not be used
together.
- Mappers can have any number of gateways, but keep the number small
- for speed. The order in which gateways are used should not
- matter.
+ Mappers can have any number of gateways. The order in which
+ gateways are used should not matter.
The 'enabled' attribute lets you disable an unwanted inherited
gateway. To do this, set the 'enabled' attribute to 'false' and
@@ -230,58 +220,28 @@
<classifier
- [name="..."]
- factory="..." | use="..."
- [ enabled="..." ]
- [ param="..." ] />
-
- <keygen
- [name="..."]
- factory="..." | use="..."
- [ enabled="..." ]
- [ param="..." ] />
-
- Declares a classifier or keychain generator component. The 'name'
- attribute is required for reusable components but should not be
- present otherwise. Either 'factory' or 'use' is required. The
- 'enabled' and 'param' attributes are optional. The 'param'
- attribute is valid only when a 'factory' is provided. This
- element accepts no child elements.
-
- Most mappers have neither a classifier nor a keychain generator.
- Those that have either kind of component are called domain
- mappers, meaning that the mapper marks the root object of an
- application domain. The root mapper is always a domain mapper.
-
- You can use a 'classifier' or 'keygen' element to declare either a
- reusable component, by placing it outside any mapper element, or a
- non-reusable component, by placing it inside a mapper element.
- Reusable components get added to a global but type-specific
- namespace. Non-reusable classifiers and keychain generators do
- not have a name.
-
- Use a Python class to implement a new classifier or keychain
- generator, then use the 'factory' attribute to link your class
- into Ape. Specify a fully-qualified class name. If your class
- constructor requires a parameter, you may pass one string
- parameter using the 'param' attribute.
-
- To import a reusable component into a mapper, add a component
- declaration to a 'mapper' element, specifying the name of the
- component to import in the 'use' attribute of the component
- declaration. The 'factory' and 'use' attributes can not be used
- together.
+ factory="..." | use="..." />
- The 'enabled' attribute lets you disable an unwanted inherited
- component. To do this, set the 'enabled' attribute to 'false'.
+ <oid-generator
+ factory="..." | use="..." />
+ Declares the classifier or OID generator component. Either
+ 'factory' or 'use' is required. This element accepts no child
+ elements.
+
+ Use a Python class to implement a new classifier or OID generator,
+ then use the 'factory' attribute to link your class into Ape.
+ Specify a fully-qualified class name. If your class constructor
+ requires parameters, you may add them to the end of the 'factory'
+ attribute in parentheses. (Only positional arguments are
+ supported.)
<use-for
[ class="..." ]
[ extensions="..." ]
- [ fallback="..." ]
- [ key="..." ] />
+ [ generic="..." ]
+ [ oid="..." ] />
The 'use-for' directive tells a classifier to use a particular
mapper when a condition is met. The 'use-for' directive must
@@ -302,9 +262,9 @@
Zope with no extension and store it in a mounted Ape filesystem,
Ape will append the default extension automatically.
- The 'fallback' attribute tells the classifier to use this mapper
+ The 'generic' attribute tells the classifier to use this mapper
for objects or filesystem nodes with no other classification. The
- allowable values for the 'fallback' attribute vary by classifier,
+ allowable values for the generic' attribute vary by classifier,
but the Zope 2 classifier recognizes the following values:
- 'directory': Use this mapper for filesystem directories.
@@ -317,29 +277,30 @@
- 'fileish_object': Use this mapper for objects that do not
extend ObjectManager.
- Again, the 'fallback' registrations only apply when no other
+ - 'basepath': Use this mapper for the Zope 2 Application object.
+
+ Again, the 'generic' registrations only apply when no other
classification is available.
- The 'key' attribute tells the classifier to use this mapper when
- the last key of the keychain matches the attribute value. This is
- useful for Zope's site-wide Application object, since it always
- has a particular keychain.
-
- Registrations made by 'use-for' get applied to the parent mapper's
- classifier. If two mappers make conflicting registrations (such
- as two mappers trying to use the same filename extension), Ape
- will detect a conflict. If you need to override a registration
- made by another mapper, you should use a variation.
+ The 'oid' attribute tells the classifier to use this mapper when
+ the OID of the object being loaded or stored matches the attribute
+ value. This is useful for the ZODB root object, since it always
+ has a particular OID.
+
+ If two mappers make conflicting registrations (such as two mappers
+ trying to use the same filename extension), Ape will detect a
+ conflict. If you need to override a registration made by another
+ mapper, you should use a variation.
<option name="..." value="..." />
The 'option' directive registers an mapper-specific option with
- the parent's classifier. The 'option' directive must descend from
- a 'mapper' element and accepts no children. The 'name' and
- 'value' attributes are both required. A mapper element can
- contain any number of 'use-for' directives.
+ the classifier. The 'option' directive must descend from a
+ 'mapper' element and accepts no children. The 'name' and 'value'
+ attributes are both required. A mapper element can contain any
+ number of 'use-for' directives.
The one option that is currently available is specific to the Zope
2 classifier. The 'content_type_attr' tells the classifier that
=== Products/Ape/doc/outline.txt 1.2 => 1.3 ===
--- Products/Ape/doc/outline.txt:1.2 Wed Jul 30 17:32:53 2003
+++ Products/Ape/doc/outline.txt Mon Mar 15 23:56:40 2004
@@ -1,8 +1,8 @@
-ApeLib Tutorial Outline
+Ape Tutorial Outline
-I. Purpose of ApeLib
+I. Purpose of Ape
A. Differences Between Object-Oriented and Relational Databases
@@ -71,14 +71,14 @@
advantage of relational data storage and locks out other
programming languages.
- ApeLib bridges the gap between ZODB and relational data storage.
+ Ape bridges the gap between ZODB and relational data storage.
It lets developers store ZODB objects in arbitrary databases and
arbitrary formats, without changing application code. It combines
the advantages of orthogonal persistence with relational storage.
D. Current Limitations
- To facilitate distribution, ApeLib is currently a Zope product. This
+ To facilitate distribution, Ape is currently a Zope product. This
makes it difficult to reuse outside Zope. But work is underway to
separate it from Zope, starting with the creation of a top-level
Python package called apelib.
@@ -87,23 +87,22 @@
A portion of Martin Fowler's book "Patterns of Enterprise
Application Architecture" describes patterns used in mapping objects
- to relational databases. A lot of the names used in ApeLib come
+ to relational databases. A lot of the names used in Ape come
from the book.
- There are many kinds of components in ApeLib, but to store new kinds
+ There are many kinds of components in Ape, but to store new kinds
of objects or store in new formats, you generally only need to write
components that implement one of two interfaces: ISerializer and
IGateway. This tutorial focuses on these two kinds of components.
A. Mappers
- ApeLib uses a tree of mappers to map objects to databases.
- Mappers are components that implement a simple interface. Mappers
- serialize, deserialize, store, load, classify, and identify
- objects. 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.
+ Ape uses a set of mappers to map objects to databases. Mappers
+ are components that implement a simple interface. Mappers
+ serialize, deserialize, store, and load objects. 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.
Most mappers are responsible for loading and storing instances of
one class. Mappers separate serialization from storage, making it
@@ -114,33 +113,33 @@
B. Basic Sequence
- To load an object, ApeLib requests that the composite gateway of a
- specific mapper load data. Composite gateways delegate the
- request to multiple specific gateways. The specific gateways each
- query the database and return a result. The composite gateway
- combines the results into a dictionary that maps gateway names to
- the results from the data store.
-
- Then ApeLib feeds that dictionary to the composite serializer of
- the same mapper. The composite serializer delegates the work of
- deserialization to multiple serializers. The serializers install
- the loaded data into the object being deserialized. Finally,
+ To load an object, Ape requests that the gateway of a specific
+ mapper load data. The gateway queries the database and return a
+ result. Gateways may delegate the request to multiple simple
+ gateways. A gateway that delegates in this manner is called a
+ composite gateway. The composite gateway combines the results
+ into a dictionary that maps gateway names to the results from the
+ data store.
+
+ Then Ape feeds that result to the mapper's serializer, which may
+ exist on a separate machine from the gateway. The serializer
+ installs the loaded data into the object being deserialized. Like
+ gateways, serializers can also be organized as a composite
+ serializer delegating to multiple simple serializers. Finally,
control returns to the application.
When storing objects, the system uses the same components, but in
- reverse order. The composite serializer reads the object and the
- results are fed to the composite gateway, which stores the data.
+ reverse order. The serializer reads the object and the results
+ are fed to the gateway, which stores the data.
ZODB is the key to loading and storing objects at the right time.
- The Persistent base class arranges for a separate data manager
- object to load the state of an object only when it is needed. The
- Persistent base class also notifies the data manager when an
- attribute of a managed object changes.
+ The Persistent base class notifies Ape when an object needs to be
+ loaded or stored.
C. Schemas
Schemas define the format of the data passed between serializers
- and gateways. ApeLib defines three basic schema classes and
+ and gateways. Ape defines three basic schema classes and
allows you to use other kinds schemas.
A FieldSchema declares that the data passed is a single field,
@@ -158,7 +157,7 @@
fields at once. When using a RowSequenceSchema, the state passed
between serializers and gateways is a sequence of tuples.
- The only requirement ApeLib makes of schemas is that they
+ The only requirement Ape makes of schemas is that they
implement the Python equality operation (__eq__), allowing the
system to verify that serializers and gateways are compatible.
You can use many kinds of Python objects as schemas.
@@ -167,7 +166,7 @@
Gateways load and store serialized state. The gateways you create
can store data anywhere and in any format, as long as you obey a
- few simple
+ few simple rules.
The state returned by the gateway's load() method must conform to
the schema declared by the gateway. Conversely, the gateway can
@@ -177,8 +176,8 @@
The gateway must generate a hash of the stored state, allowing the
system to detect transaction conflicts. The hash is returned by
both the load() and store() methods. Hashes don't need to be
- integers, but it must be possible to convert hashes to integers
- using Python's hash() function.
+ integers, but must be hashable as defined by Python's hash()
+ function.
E. Serializers
@@ -191,20 +190,19 @@
these questions, serializers receive event objects as arguments to
the serialize() and deserialize() methods. By interacting with
the events, the serializer affects the serialization and
- deserialization processes to get the proper behavior.
+ deserialization processes to achieve the proper behavior.
1. What if the serializer forgets to store an attribute?
To avoid forgetting attributes, serializers indicate to the
serialization event which attributes and subobjects they
- serialized by calling the notifySerialized() or
- ignoreAttribute() method. (The difference between the two
- methods will be explained in a moment.) At the end of
- serialization, a final serializer may look for any remaining
- attributes. If there are any attributes left over, the final
- serializer may choose to either put the rest of the attributes
- in a pickle or raise an exception indicating which attributes
- were forgotten.
+ serialized by calling the serialized() or ignore() method. (The
+ difference between the two methods will be explained in a
+ moment.) At the end of serialization, a final serializer may
+ look for any remaining attributes. If there are any attributes
+ left over, the final serializer may choose to either put the
+ rest of the attributes in a pickle or raise an exception
+ indicating which attributes were forgotten.
2. What if two attributes refer to the same subobject under
different attribute names? In general, what if an object refers
@@ -219,13 +217,13 @@
could generate a second copy of the subobject upon
deserialization.
- To deal with this, serializers call the notifySerialized() event
- rather than the ignoreAttribute() method. The
- notifySerialized() method provides the information needed by the
- final serializer to restore references to the correct subobject.
- For this to work, serializers also need to call
- notifyDeserialized() in their deserialize() method, so that the
- unpickler knows exactly what subobject to refer to.
+ To deal with this, serializers call the serialized() method
+ rather than the ignore() method. The serialized() method
+ provides the information needed by the final serializer to
+ restore references to the correct subobject. For this to work,
+ serializers also need to call deserialized() in their
+ deserialize() method, so that the unpickler knows exactly what
+ subobject to refer to.
3. Is it possible to avoid loading the whole database into RAM
when deserializing? Conversely, after making a change, is it
@@ -241,41 +239,40 @@
During serialization, serializers use three methods of the
serialization event to make references to other database
- records. Serializers first call identifyObject() to find out if
- the subobject is already stored in the database. If it isn't,
- the serializer should call makeKey() to generate an identity for
- the new subobject. In either case, the serializer then calls
- notifySerializedRef() to tell the event that it is storing a
- reference to another database record.
-
- During deserialization, serializers can use the dereference()
- method of the deserialization event to refer to objects from
- other database records without loading the full state of the
- objects. The returned subobject may be in a "ghosted" state,
- meaning that it temporarily has no attributes. (When you
- attempt to access any attribute of a ghosted object, ZODB
- transparently loads the object before looking for the
- attribute.)
+ records. Serializers first call identify() to find out if the
+ subobject is already stored in the database. If it isn't, the
+ serializer should call new_oid() to generate an identity for the
+ new subobject. In either case, the serializer then calls
+ referenced() to tell the event that it is storing a reference to
+ another database record.
+
+ During deserialization, serializers can use the resolve() method
+ of the deserialization event to refer to objects from other
+ database records without loading the full state of the objects.
+ The returned subobject may be in a "ghosted" state, meaning that
+ it temporarily has no attributes. (When you attempt to access
+ any attribute of a ghosted object, ZODB transparently loads the
+ object before looking for the attribute.)
4. What if the record boundaries set up by the serializer don't
correspond directly with ZODB objects?
- ZODB makes an assumption that isn't always valid in ApeLib: ZODB
+ ZODB makes an assumption that isn't always valid in Ape: ZODB
assumes that objects that derive from the Persistent base class
- are database record boundaries. In ApeLib, sometimes it makes
+ are database record boundaries. In Ape, sometimes it makes
sense to serialize several Persistent objects in a single
database record.
However, when you serialize more than one Persistent object in a
single record, you create what are called "unmanaged" persistent
- objects or "UPOs". If the serializer does tell ApeLib about the
+ objects or "UPOs". If the serializer does tell Ape about the
UPOs, ZODB will not see changes made to them and transactions
involving changes to those objects may be incomplete. So during
both serialization and deserialization, it is important for
- ZODB-aware serializers to call the event's
- addUnmanagedPersistentObjects() method.
+ ZODB-aware serializers to append to the event's 'upos'
+ attribute.
- ApeLib provides some useful standard serializers:
+ Ape provides some useful standard serializers:
- The remainder serializer pickles and restores all the
attributes not stored by other serializers. This is useful for
@@ -288,11 +285,11 @@
either. The roll call serializer stores nothing, so it does not
need to be paired with a gateway.
- - The optional serializer is a wrapper (decorator) around a real
- serializer. The optional serializer asks the real serializer if
- it is able to serialize or deserialize an object (using the
- canSerialize() method). If the test fails, the optional
- serializer ignores the failure and falls back to a default.
+ - The optional serializer is a decorator for a real serializer.
+ The optional serializer asks the real serializer if it is able
+ to serialize or deserialize an object (using the canSerialize()
+ method). If the test fails, the optional serializer ignores the
+ failure and falls back to a default.
- The "any class" serializer is a composite serializer which,
unlike the standard "known class" composite serializer, can
@@ -300,7 +297,8 @@
deserialization, it defers the creation of a class instance
until the classification of the object is known. The "any
class" serializer incurs performance penalties, but it allows
- ApeLib to work with heterogeneous object systems like Zope.
+ Ape to work with extremely heterogeneous object systems like
+ Zope.
Serializers access the innards of objects, often breaking
encapsulation because the serializers need to know exactly what
@@ -310,73 +308,59 @@
F. Classifiers
- With all this talk of heterogeneous object systems, two important
- questions have not been answered yet. How do you choose what kind
- of object to create when loading a database record? And how do
- you choose what kind of database record to create when storing an
- object? When working with relational databases, these are not
- usually difficult to answer, but in the world of MIME types,
- filename extensions, and peer-to-peer distribution, it's more
- difficult. The logic for choosing mappers must be componentized.
-
Classifiers are the components that choose which mapper to use for
- an object or database record. Classifiers can be simple, always
- using a specific mapper for specific OIDs or storing the name of
- the mapper in the database. Classifiers can also be complex,
- using attributes or metadata to make the choice of mapper.
-
- The root mapper holds the main classifier. ApeLib consults the
- main classifier when loading and storing any object except the
- root object. For Zope 2, the main classifier, a
- MetaTypeClassifier, is fairly complex, involving meta_types,
- filename extensions, and class names. Fortunately, the
- MetaTypeClassifier is the only component that knows about
- meta_types and so forth, so other applications that use ApeLib do
- not need all that complexity.
+ an object or database record. There is one classifier per object
+ database. Classifiers can be simple, always using a specific
+ mapper for specific OIDs or storing the name of the mapper in the
+ database. Classifiers can also be complex, using attributes or
+ metadata to make the choice of mapper.
+
+ Ape consults the classifier before loading or storing any object.
+ The standard classifier Ape uses for Zope 2 object databases is
+ fairly complex, involving meta_types, filename extensions, and
+ class names. There is also a simpler classifier in apelib.core.
- Classifiers also work with "classifications". Classifications are
+ Classifiers work with "classifications". Classifications are
dictionaries mapping strings to strings. Classifications contain
information that might be useful for choosing object and database
record types. Unlike the rest of the state of an object,
classifications do not need to be precise.
- When loading an object, ApeLib calls the classifier's
- classifyState() method. The classifier may choose to load
- information from the database to discover the type of database
- record. (It usually does this using a gateway private to the
- classifier.) classifyState() returns a classification and mapper
- name.
+ When loading an object, Ape calls the classifier's classifyState()
+ method. The classifier may choose to load information from the
+ database to discover the type of database record. It usually does
+ this using a gateway private to the classifier. classifyState()
+ returns a classification.
- When storing an object, ApeLib calls the classifier's
+ When storing an object, Ape calls the classifier's
classifyObject() method. The classifier may choose to examine the
object or it may know enough just by the keychain assigned to the
object. classifyObject() returns a classification and
mapper_name, but it should not store the generated classification
- yet. ApeLib later calls the store() method of the classifier, at
+ yet. Ape later calls the store() method of the classifier, at
which point the classifier has the option of storing the
classification. (This separation exists so that serialization and
- data storage can theoretically occur on different machines, which
- ZEO does.)
+ data storage can occur on different machines.)
III. Example: Mapping Zope 2
- ApeLib provides two default Zope 2 mappers. One maps to the
- filesystem and the other maps to a PostgreSQL database. Both are
- configured through apeconf.xml files. See apexml.txt for more
- details on the configuration files.
-
- The PostgreSQL mapper uses the Psycopg module to connect to the
- database. It uses integers as keys and puts information about
- each object in several tables. All objects have an entry in the
- classification table. The PostgreSQL mapper uses a simple schema,
- but ApeLib is not limited to this schema.
+ The 'apeconf.xml' file in 'apelib.zope2' provides two variations of
+ a Zope 2 mapper configuration. To extend the Zope 2 mappers with
+ your own mappers, write an apeconf.xml file and place it in your
+ Zope 2 product. One maps to the filesystem and the other maps to a
+ SQL database. See apexml.txt for more details on apeconf.xml.
+
+ The SQL mapper uses a Python DB-API 2.0 module to connect to the
+ database. It uses integers as keys and puts information about each
+ object in several tables. All objects have an entry in the
+ classification table. The SQL mapper uses a simple schema, but Ape
+ is not limited to this schema.
The filesystem mapper stores data in a directory and its
- subdirectories. It uses paths as keys and puts information about
- each object in up to three files. The filesystem mapper both
- recognizes and generates filename extensions, but it can also work
- without filename extensions.
+ subdirectories. It annotates files and directories using
+ ".properties" files. The filesystem mapper both recognizes and
+ generates filename extensions.
Normally, ZODB caches objects indefinitely. This leads to excellent
performance, but in the case of Ape, it prevents the object system
@@ -392,91 +376,25 @@
solution could potentially work even better with RDBMSs, since the
periodic scan could be implemented using only a single query.
- To extend the Zope 2 mappers with your own mappers, write an
- apeconf.xml file and place it in your Zope 2 product. See
- apexml.txt for more information.
-
-
-IV. Multiple domains
-
- Until now, this paper has assumed that given nothing more than an
- object or a database record, ApeLib can choose a mapper for that
- object. That assumption is reasonable until you start using generic
- object types for many parts of an application, and you need to store
- the generic objects differently depending on what part of the
- application is using them. For example, ZODB BTrees are reusable
- for many purposes, but storing both catalog indexes and user records
- in the same database tables would not be sensible.
-
- Also note that the acquisition wrappers and context wrappers
- normally available in Zope are not available when loading and
- storing objects. ZODB works with bare objects, so no wrappers are
- available to discover the context of an object while loading and
- storing it.
-
- Therefore, ApeLib provides a different facility for preserving the
- context of objects and database records. Instead of looking up a
- mapper by key, ApeLib uses a list of keys or "keychain" to visit a
- tree of mappers. Specifically, to find the right mapper, ApeLib
- asks the classifier of the root mapper to choose a mapper, then it
- asks the classifier of the chosen mapper to choose a mapper, and so
- on, until it has followed each key in a keychain and arrived at the
- right mapper.
-
- ApeLib calls mappers that link to other mappers "domain mappers".
- Not all mappers are domain mappers. The root mapper is a domain
- mapper, but currently no other mappers in the Zope 2 example are
- domain mappers.
-
- Unlike simple mappers, domain mappers provide a classifier, a
- keychain generator, and sub-mappers. Classifiers have been
- discussed before. Keychain generators isolate the logic of
- generating keychains from serializers and gateways. Serializers and
- gateways can generate their own keychains if they want, but
- serializers are more reusable when they remain independent of the
- contents of keys and keychains.
-
- Note that the tree of object mappers does not necessarily look like
- the tree of objects in an application. Even though Zope stores a
- tree of objects like a filesystem, most of the mappers used in
- ApeLib's Zope 2 mapper are attached to the root mapper. In Zope,
- most kinds of containers can contain most kinds of objects. A tree
- of Zope object mappers could be confining, permitting certain
- objects to be stored in only certain kinds of containers.
-
- However, for some applications, containment constraints might be a
- major benefit. Besides helping consistency, domain mappers
- encapsulate object mapping details in smaller, independent objects.
- Domain mappers minimize the possibility of collision with other
- parts of the application that want to map objects to the same
- database. But avoid excessively long keychains, since ApeLib must
- examine each key in a keychain repeatedly.
-
- As an alternative to keychains with multiple keys, applications
- might instead set up a separate data manager for different parts of
- the application. This strategy allows domain-specific caching
- strategies, but it also sacrifices some amount of database
- independence.
-V. Ways to use the framework
+IV. Ways to use the framework
- ZEO: ApeLib separates serialization from data storage, making it
+ ZEO: Ape separates serialization from data storage, making it
possible to perform serialization on a ZEO client while data storage
happens in a ZEO server. ZEO also adds the ability to keep a very
large object cache. Ape has been successfully tested with ZEO 3.2.
- Zope 3: ApeLib is currently designed with Zope 2 in mind, but meant
+ Zope 3: Ape is currently designed with Zope 2 in mind, but meant
to be reusable for Zope 3. A new set of mappers will be needed, but
nearly all of the interfaces should remain unchanged.
- Non-Zope applications: ApeLib is a distinct library useful for many
- ZODB applications. ApeLib makes it easier to map objects to any
+ Non-Zope applications: Ape is a distinct library useful for many
+ ZODB applications. Ape makes it easier to map objects to any
data store.
Finally, the framework is useful for many purposes outside ZODB.
Once you have built a system of mappers, you can use those mappers
to import and export objects, synchronize with a data store, and
- apply version control to your objects. The concepts behind ApeLib
+ apply version control to your objects. The concepts behind Ape
open exciting possibilities.
-
More information about the Zope-CVS
mailing list