Commit 7cda893c authored by Chris McDonough's avatar Chris McDonough

- Permission name changes.

- Removed advanced (import/export) view - superfluous.

- new() and new_or_existing() methods now accept a wrap_with argument.
  If wrap_with is non-None, the data object returned will be wrapped
  in (via __of__) with the object passed into the wrap_with argument.
  This will facilitate the wrapping of data objects in the calling
  session data manager object.

- Transient objects no longer keep a reference to their container.
  Instead, containers use the isValid method of objects to determine
  whether an object is valid.  An object no longer deletes itself from
  its container and relies solely on this mechanism.

- Callback handling now logs on failure.

- Various deletions of commented material.

- getToken of data objects returns the key with which they were entered
  into their container, while getId returns a uniform unique id.  getName
  is now aliased to getId.

- data objects now no longer aq-unwrap things stored in them.  This
  is a security change.

- repr method of data object now returns simpler structure.

- removed stx workarounds from interfaces file (we should just fix the
  help system instead of doing stuff like  _, etc.)

- extended some descriptions of interfaces.

- extended and edited other docs.

TODO:

- fix tests to run under testrunner.

- "ring" must change to become more conflict resistant.
  (new data structure and algorithm needs to be put in)

-  need new icon for data container.

- need out of memory protection in container.
parent 205b5b17
...@@ -77,7 +77,8 @@ ...@@ -77,7 +77,8 @@
""" """
Transient Objects Transient Objects
TransientObjectContainers implement: TransientObjectContainers are objects which contain zero or more
TransientObjects. They implement the following interfaces:
- ItemWithId - ItemWithId
...@@ -85,16 +86,24 @@ Transient Objects ...@@ -85,16 +86,24 @@ Transient Objects
- TransientItemContainer - TransientItemContainer
In particular, one uses the 'new_ _or_ _existing' method on In particular, one uses the 'new_or_existing' method on
TransientObjectContainers to retrieve or create a TransientObject based TransientObjectContainers to retrieve or create a TransientObject
on a given string key. based on a given string key.
If add or delete notifications are registered with the container, they If add or delete notifications are registered with the container,
will be called back when items in the container are added or deleted, they will be called back when items in the container are added or
with the item and the container as arguments. The callbacks may be deleted, with the item and the container as arguments. The
registered either as bound methods, functions, or named paths in Zope. callbacks may be registered either as bound methods, functions, or
physical paths to Zope Script (Python Script or External Method)
TransientObjects implement: objects (e.g. '/some/resolvable/script/name'). In any of these
cases, the delete and add notifications will be called with
arguments allowing the callbacks to operate on data representing the
state of the transient object at the moment of addition or deletion
(see setAddNotificationTarget and setDelNotificationTarget below).
TransientObjects are containerish items held within
TransientObjectContainers and they implement the following
interfaces:
- ItemWithId - ItemWithId
...@@ -106,7 +115,28 @@ Transient Objects ...@@ -106,7 +115,28 @@ Transient Objects
- ImmutablyValuedMappingOfPickleableObjects - ImmutablyValuedMappingOfPickleableObjects
""" Of particular importance is the idea that TransientObjects do not
offer the contract of "normal" ZODB container objects; mutations
made to items which are contained within a TransientObject cannot be
expected to persist. Developers need explicitly resave the state of
a subobject of a TransientObject by placing it back into the
TransientObject via the TransientObject.__setitem__ or .set methods.
This requirement is due to the desire to allow people to create
alternate TransientObject implementations that are *not* based on
the ZODB. Practically, this means that when working with a
TransientObject which contains mutable subobjects (even if they
inherit from Persistence.Persistent), you *must* resave them back
into the TransientObject. For example::
class Foo(Persistence.Persistent):
pass
transient_object = transient_data_container.new('t')
foo = transient_object['foo'] = Foo()
foo.bar = 1
# the following is *necessary* to repersist the data
transient_object['foo'] = foo
"""
import Interface import Interface
...@@ -119,6 +149,13 @@ class Transient(Interface.Base): ...@@ -119,6 +149,13 @@ class Transient(Interface.Base):
related to this object to be called as a side effect. related to this object to be called as a side effect.
""" """
def isValid(self):
"""
Return true if transient object is still valid, false if not.
A transient object is valid if its invalidate method has not been
called.
"""
def getLastAccessed(self): def getLastAccessed(self):
""" """
Return the time the transient object was last accessed in Return the time the transient object was last accessed in
...@@ -178,23 +215,24 @@ class DictionaryLike(Interface.Base): ...@@ -178,23 +215,24 @@ class DictionaryLike(Interface.Base):
class ItemWithId(Interface.Base): class ItemWithId(Interface.Base):
def getId(self): def getId(self):
""" """
Returns a meaningful unique id for the object. Returns a meaningful unique id for the object. Note that this id
need not the key under which the object is stored in its container.
""" """
class TTWDictionary(DictionaryLike, ItemWithId): class TTWDictionary(DictionaryLike, ItemWithId):
def set(self, k, v): def set(self, k, v):
""" """
Call _  _setitem_  _ with key k, value v. Call __setitem__ with key k, value v.
""" """
def delete(self, k): def delete(self, k):
""" """
Call _  _delitem_  _ with key k. Call __delitem__ with key k.
""" """
def __guarded_setitem__(self, k, v): def __guarded_setitem__(self, k, v):
""" """
Call _  _setitem_  _ with key k, value v. Call __setitem__ with key k, value v.
""" """
class ImmutablyValuedMappingOfPickleableObjects(Interface.Base): class ImmutablyValuedMappingOfPickleableObjects(Interface.Base):
...@@ -209,11 +247,10 @@ class ImmutablyValuedMappingOfPickleableObjects(Interface.Base): ...@@ -209,11 +247,10 @@ class ImmutablyValuedMappingOfPickleableObjects(Interface.Base):
Returns the value associated with key k. Returns the value associated with key k.
Note that no guarantee is made to persist changes made to mutable Note that no guarantee is made to persist changes made to mutable
objects obtained via _  _getitem_  _, even if objects obtained via __getitem__, even if they support the ZODB
they support the ZODB Persistence interface. In order to ensure Persistence interface. In order to ensure that changes to mutable
that changes to mutable values are persisted, you need to explicitly values are persisted, you need to explicitly put the value back in
put the value back in to the mapping via the to the mapping via __setitem__.
_  _setitem_  _.
""" """
def __delitem__(self, k): def __delitem__(self, k):
...@@ -228,16 +265,10 @@ class HomogeneousItemContainer(Interface.Base): ...@@ -228,16 +265,10 @@ class HomogeneousItemContainer(Interface.Base):
2. Is responsible for the creation of its subobjects. 2. Is responsible for the creation of its subobjects.
3. Allows for the access of a subobject by key. 3. Allows for the access of a subobject by key.
""" """
def getSubobjectInterface(self):
"""
Returns the interface object which must be supported by items added
to or created by this container.
"""
def get(self, k, default=None): def get(self, k, default=None):
""" """
Return value associated with key k. If value associated with k does Return value associated with key k via __getitem__. If value
not exist, return default. associated with k does not exist, return default.
""" """
def has_key(self, k): def has_key(self, k):
...@@ -252,7 +283,7 @@ class HomogeneousItemContainer(Interface.Base): ...@@ -252,7 +283,7 @@ class HomogeneousItemContainer(Interface.Base):
""" """
class StringKeyedHomogeneousItemContainer(HomogeneousItemContainer): class StringKeyedHomogeneousItemContainer(HomogeneousItemContainer):
def new(self, k): def new(self, k, wrap_with=None):
""" """
Creates a new subobject of the type supported by this container Creates a new subobject of the type supported by this container
with key "k" and returns it. with key "k" and returns it.
...@@ -260,17 +291,25 @@ class StringKeyedHomogeneousItemContainer(HomogeneousItemContainer): ...@@ -260,17 +291,25 @@ class StringKeyedHomogeneousItemContainer(HomogeneousItemContainer):
If an object already exists in the container with key "k", a If an object already exists in the container with key "k", a
KeyError is raised. KeyError is raised.
If wrap_with is non-None, the subobject is returned in the
acquisition context of wrap_in, else it is returned in
the acquisition context of this transient object container.
"k" must be a string, else a TypeError is raised. "k" must be a string, else a TypeError is raised.
""" """
def new_or_existing(self, k): def new_or_existing(self, k, wrap_with=None):
""" """
If an object already exists in the container with key "k", it If an object already exists in the container with key "k", it
is returned. is returned.
Otherwiser, create a new subobject of the type supported by this Otherwise, create a new subobject of the type supported by this
container with key "k" and return it. container with key "k" and return it.
If wrap_with is non-None, the subobject is returned in the
acquisition context of wrap_in, else it is returned in
the acquisition context of this transient object container.
"k" must be a string, else a TypeError is raised. "k" must be a string, else a TypeError is raised.
""" """
...@@ -289,32 +328,45 @@ class TransientItemContainer(Interface.Base): ...@@ -289,32 +328,45 @@ class TransientItemContainer(Interface.Base):
def getAddNotificationTarget(self): def getAddNotificationTarget(self):
""" """
Returns the current 'after add' function, or None. Returns the currently registered 'add notification' value, or None.
""" """
def setAddNotificationTarget(self, f): def setAddNotificationTarget(self, f):
""" """
Cause the 'after add' function to be 'f'. Cause the 'add notification' function to be 'f'.
If 'f' is not callable and is a string, treat it as a physical
path to a Zope Script object (Python Script, External Method,
et. al).
If 'f' is not callable and is a string, treat it as a Zope path to 'add notify' functions need accept two arguments: 'item',
a callable function. which is the transient object being destroyed, and 'container',
which is the transient object container which is performing
the destruction. For example::
'after add' functions need accept a single argument: 'item', which def addNotify(item, container):
is the item being added to the container. print "id of 'item' arg was %s" % item.getId()
""" """
def getDelNotificationTarget(self): def getDelNotificationTarget(self):
""" """
Returns the current 'before destruction' function, or None. Returns the currently registered 'delete notification' value, or
None.
""" """
def setDelNotificationTarget(self, f): def setDelNotificationTarget(self, f):
""" """
Cause the 'before destruction' function to be 'f'. Cause the 'delete notification' function to be 'f'.
If 'f' is not callable and is a string, treat it as a physical
path to a Zope Script object (Python Script, External Method,
et. al).
If 'f' is not callable and is a string, treat it as a Zope path to 'Before destruction' functions need accept two arguments: 'item',
a callable function. which is the transient object being destroyed, and 'container',
which is the transient object container which is performing
the destruction. For example::
'before destruction' functions need accept a single argument: 'item', def delNotify(item, container):
which is the item being destroyed. print "id of 'item' arg was %s" % item.getId()
""" """
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
""" """
Transience initialization routines Transience initialization routines
$Id: __init__.py,v 1.3 2001/11/02 20:44:22 matt Exp $ $Id: __init__.py,v 1.4 2001/11/07 06:46:36 chrism Exp $
""" """
import Transience import Transience
...@@ -93,7 +93,7 @@ import Transience ...@@ -93,7 +93,7 @@ import Transience
def initialize(context): def initialize(context):
context.registerClass( context.registerClass(
Transience.TransientObjectContainer, Transience.TransientObjectContainer,
permission=Transience.ADD_DATAMGR_PERM, permission=Transience.ADD_CONTAINER_PERM,
icon='www/datacontainer.gif', icon='www/datacontainer.gif',
constructors=(Transience.constructTransientObjectContainerForm, constructors=(Transience.constructTransientObjectContainerForm,
Transience.constructTransientObjectContainer) Transience.constructTransientObjectContainer)
......
<dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _,
form_title='Change Transient Object Container',
help_product='Transience',
help_topic='Transience-export.stx'
)">
<div class="form-help">
Transient object data will be imported/exported to/from the file
'var/transientobjects.zexp' on your server's hard disk in your Zope
directory.
</div>
<br>
<table>
<tr>
<td align="left" valign="top">
<form action="manage_exportTransientObjects" method="post">
<input class="form-element" type=submit name=submit value="Export Transient Objects">
</form>
</td>
<td width="20%">&nbsp;</td>
<td align="left" valign="top">
<form action="manage_importTransientObjects" method="post">
<input class="form-element" type=submit name=submit value="Import Transient Objects">
</form>
</td>
</tr>
</table>
<dtml-var manage_page_footer>
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
<em>Title</em> Title
</div> </div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
...@@ -51,22 +51,10 @@ ...@@ -51,22 +51,10 @@
</td> </td>
</tr> </tr>
<tr>
<td>
<p>
Transient Object Containers support <b>Notification Targets</b> which
are methods which are invoked when transient objects are added or deleted
from the container. A notification target is invoked with the item being
operated upon, and the transient object container as arguments. Specify
the path to the method to be invoked to receive the notification.
</p>
</td>
</tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
<em>Add Notification Target</em> Add Notification Target
</div> </div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
...@@ -78,7 +66,7 @@ the path to the method to be invoked to receive the notification. ...@@ -78,7 +66,7 @@ the path to the method to be invoked to receive the notification.
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
<em>Delete Notification Target</em> Delete Notification Target
</div> </div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
...@@ -107,7 +95,7 @@ the path to the method to be invoked to receive the notification. ...@@ -107,7 +95,7 @@ the path to the method to be invoked to receive the notification.
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
<font color="red">WARNING!</font> <font color="red">WARNING!</font>
The data objects currently existing in this session data container The data objects existing in this transient object container
will be deleted when the data object timeout is changed. will be deleted when the data object timeout is changed.
</div> </div>
</td> </td>
......
TransientObjectContainer - Change TransientObjectContainer - Manage
Transient Object Containers Transient Object Containers
A TransientObjectContainer contains objects which will expire after A TransientObjectContainer contains objects which will expire after
a given period of time. A TransientObjectContainer is used by a given period of time. A TransientObjectContainer is used by
SessionDataMangers to store session information. a SessionDataManager to store session data.
To change a TransientObjectContainer, specify the following: To change a TransientObjectContainer, specify the following:
- *title* - **Title**
The title of the object. The title of the object (optional).
- **timeout_minutes** - **Data object timeout in minutes**
The minimum number of minutes that objects in the container will The minimum number of minutes that objects in the container will
persist for. Objects in the container are passively deleted, so persist for. Objects in the container are passively deleted, so
...@@ -21,29 +21,38 @@ TransientObjectContainer - Change ...@@ -21,29 +21,38 @@ TransientObjectContainer - Change
If you change the timeout value, all objects in the transient If you change the timeout value, all objects in the transient
container will be flushed. container will be flushed.
- *addNotification* The default is 20 minutes.
The name of an object to receive notifications when objects are - **Add Notification Target**
added to the TransientObjectContainer. See NotificationTargets.
- *delNotification* The physical path of a script which will receive notifications when
objects are added to the TransientObjectContainer. See
NotificationTargets below. Ex: '/path/to/addNotificationMethod'.
The name of an object to receive notifications when objects are - **Delete Notification Target**
deleted from the TransientObjectContainer. See NotificationTargets.
The physical path of a script which will receive notifications when
objects are deleted from the TransientObjectContainer. See
NotificationTargets below. Ex: 'path/to/delNotificationMethod'.
Notification Targets Notification Targets
A NotificationTarget is a callable (a bound method, function, or A NotificationTarget is a string representing a physical path to a
named Zope object) which is called when an object is added or removed Zope Script (Python Script or External Method) object which is
from a TransientObjectContainer. called when an object is added or removed from a
TransientObjectContainer.
NotificationTargets are called with two arguments, the first being Notification targets are called with two arguments, the first
the item being added or removed from the container, and the second being the item being added or removed from the container, and the
being the container itself. Within Zope, the container will be second being the container itself. Within Zope, the container
acquisition wrapped, allowing the container to be used as a context will be acquisition wrapped, allowing the container to be used as
to reference other Zope objects. a context to reference other Zope objects.
An example of a notification target External Method::
def notificationTarget(item, container):
from zLOG import LOG
LOG(100, 'test', 'id: %s' % item.getId())
See Also See Also
......
TransientObjectContainer - Import/Export
You may import or export transient objects *inside* a transient object
container.
For exporting, click the **Export Transient Objects** button.
The data in the transient object container will be saved to a special
file 'var/transientobjects.zexp' in your Zope directory.
For importing, click the **Import Transient Objects** button.
The data in the special file 'var/transientobjects.zexp' will be read,
creating the transient objects in your transient object container.
See Also
- "Transient Object Containers":Transience.stx
Transient Object Containers Transient Objects
Transient Object Overview A transient object is an object which persists for a limited
period of time after which it is automatically expired. The
objects which make this behavior possible are
TransientObjectContainers and TransientObjects.
A transient object persists, but for a limited period of time. Transient Object Container Overview
To facilitate persistence of items for a limited duration, the
TransientObjectContainer provides a container which stores
TransientObjects. A TransientObject is dictionary like; it
will respond to dictionary semantics. The TransientObjectContainer
maintains a time-out mechanism to flush out expired entries.
The container also has a notification mechanism whereby it can
notify a script or method that an object has been added or removed
from the container.
Using Transient Objects To facilitate persistence of items for a limited duration, a
TransientObjectContainer is a container which stores and maintains
an expiration policy related to TransientObjects.
A TransientObjectContainer flushes expired entries based on a
timeout based on last access of a contained key. It also has a
notification mechanism whereby it can notify a script or method
that an object has been added or removed from the container. When
a new item is created, the add notification target on the
container is called. Similarly, when the item is deleted, either
explicitly or by timeout, the delete notification target is
called.
One uses the 'new_or_existing' or 'new' methods of a One uses the 'new_or_existing' or 'new' methods of a
TransientObjectContainer to obtain a TransientObject. The TransientObjectContainer to obtain a TransientObject. The
TransientObjectContainer only accepts string keys to name objects; TransientObjectContainer only accepts string keys to name objects;
you may not use objects as keys. you may not use objects as keys.
When a new item is created, the add notification target on the A Transient Object is considered "expired" by a
container is notified about the object via a callback. Similarly, TransientObjectContainer when it has not been accessed in a
when the item is deleted, either explicitly or by timeout, the configurable number of minutes (the "data object timeout").
delete notification target is called back.
TransientObjects, since they behave as a dictionary, may contain
any arbitrarily keyed data. However, the TransientObject cannot inspect
the contents of what it stores to determine if it has been changed,
thus, it is important to explicitly set data on the TransientObject
itself in the event some nested data has changed and requires saving.
For example, consider the following python script::
# Create a transientObject
t = container.transient_container.new_or_existing('Foobar')
# Create a dictionary
d = {}
# Store the dictionary in the transientObject Using Transient Objects
t['d'] = d
And a similar python script::
# Retrieve our transientObject
t = container.transient_container.new_or_existing('Foobar')
# Retreive the dictionary
d = t['d']
# Update the dictionary
d[1] = 1
In this second example, the contents of the transientObject will not
be saved, because the transientObject itself was not modified. It
is important to update the object to signal it that it must save its
state.
TransientObjects are themselves "containerish" and
"dictionary-like"; they implement a dictionary-like interface as
well as methods related to manual invalidation, timeout, and
introspection.
The values of a transient object can be any pickleable Python data
structure while the keys of a transient object may be any hashable
and pickleable Python data structure.
Note that TransientObjects do not offer the contract of "normal"
ZODB container objects; mutations made to items which are
contained within a TransientObject cannot be expected to persist.
Developers need explicitly resave the state of a subobject of a
TransientObject by placing it back into the TransientObject via
the TransientObject.__setitem__ or .set methods. This requirement
is due to the desire to allow people to create alternate
TransientObject implementations that are *not* based on the ZODB.
Practically, this means that when working with a TransientObject
which contains mutable subobjects (even if they inherit from
Persistence.Persistent), you *must* resave them back into the
TransientObject. For example::
class Foo(Persistence.Persistent):
pass
transient_object = transient_data_container.new('t')
foo = transient_object['foo'] = Foo()
foo.bar = 1
# the following is *necessary* to repersist the data
transient_object['foo'] = foo
See Also See Also
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment