[Zope-Checkins] CVS: Zope/lib/python/Products/CoreSessionTracking - AutoExpireMapping.py:1.1.2.1 CHANGES.txt:1.1.2.1 README.txt:1.1.2.1 SessionData.py:1.1.2.1 SessionDataContainer.py:1.1.2.1 SessionDataManager.py:1.1.2.1 SessionFanout.py:1.1.2.1 SessionIdManager.py:1.1.2.1 SessionStorage.py:1.1.2.1 SessioningInterfaces.py:1.1.2.1 TODO.txt:1.1.2.1 VERSION.txt:1.1.2.1 __init__.py:1.1.2.1 addDataManager.dtml:1.1.2.1 addExtDataContainer.dtml:1.1.2.1 addIdManager.dtml:1.1.2.1 manageDataManager.dtml:1.1.2.1 manageExtDataContainer.dtml:1.1.2.1 manageIdManager.dtml:1.1.2.1 manageImpExpSessionData.dtml:1.1.2.1 manageIntDataContainer.dtml:1.1.2.1 manageSessionData.dtml:1.1.2.1
Matthew T. Kromer
matt@zope.com
Thu, 4 Oct 2001 15:32:28 -0400
Update of /cvs-repository/Zope/lib/python/Products/CoreSessionTracking
In directory cvs.zope.org:/tmp/cvs-serv6625/CoreSessionTracking
Added Files:
Tag: matt-CoreSessionTracking-branch
AutoExpireMapping.py CHANGES.txt README.txt SessionData.py
SessionDataContainer.py SessionDataManager.py SessionFanout.py
SessionIdManager.py SessionStorage.py SessioningInterfaces.py
TODO.txt VERSION.txt __init__.py addDataManager.dtml
addExtDataContainer.dtml addIdManager.dtml
manageDataManager.dtml manageExtDataContainer.dtml
manageIdManager.dtml manageImpExpSessionData.dtml
manageIntDataContainer.dtml manageSessionData.dtml
Log Message:
Adding CoreSessionTracking to Products
=== Added File Zope/lib/python/Products/CoreSessionTracking/AutoExpireMapping.py ===
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
import time, string
_marker = []
from Persistence import Persistent
import Acquisition
from zLOG import LOG
class AutoExpireMapping:
"""
Pure mixin to a session data container or for subclassing.
A mapping which self-manages the expiration of the objects
it contains based on user-provided timeout value and resolution
by using a ring of timed buckets.
"""
def __init__(self, timeout_mins=20, ctype=None, onend='onEnd',
err_margin=.20):
# we give ourselves a 20% error margin by default to reduce
# the number of buckets necessary
self._setTimeout(timeout_mins)
if ctype is None:
LOG('Session Tracking', 100,
('AutoExpireMapping container type set to dictionary... this'
' is likely an error'))
def ctype():
return {}
self._ctype = ctype
self._setOnEnd(onend)
self._err_margin = err_margin
self._reset()
def getTimeoutMinutes(self):
""" """
return self._timeout_secs / 60
def _setTimeout(self, timeout_mins):
# incoming timeout value is in minutes
if type(timeout_mins) is not type(1):
raise "Timeout value must be integer: %s" % timeout_mins
# convert to seconds and store, timeout must be stored as integer
self._timeout_secs = timeout_mins * 60
def _setOnEnd(self, onend):
if type(onend) is not type(''):
raise "Onend function name must be string, %s" % onend
if onend[0:1] not in string.letters:
raise "Onend function name must start with a-z, %s" % onend
self._onend = onend
def _reset(self):
self._resolution_secs = int(self._timeout_secs*self._err_margin) or 1
now = int(time.time())
ctype = self._ctype
numbuckets = self._timeout_secs/self._resolution_secs or 1
l = []
i = 0
for x in range(numbuckets):
dump_after = now + i
c = ctype()
l.insert(0, [c, dump_after])
i = i + self._resolution_secs
index = ctype()
self._ring = Ring(l, index)
def _getCurrentBucket(self, get_dump=0, time=time.time):
# no timeout always returns last bucket
if not self._timeout_secs:
b, dump_after = self._ring._data[0]
return b
index = self._ring._index
now = int(time())
i = self._timeout_secs
# expire all buckets in the ring which have a dump_after time that
# is before now, turning the ring as many turns as necessary to
# get to a non-expirable bucket.
while 1:
l = b, dump_after = self._ring._data[-1]
if now > dump_after:
self._ring.turn()
# mutate elements in-place in the ring
new_dump_after = now + i
l[1] = new_dump_after
self._clean(b, index)
i = i + self._resolution_secs
else:
break
if get_dump:
return self._ring._data[0], dump_after, now
else:
b, dump_after = self._ring._data[0]
return b
def _clean(self, b, index):
for ob in b.values():
d = last = None
f = getattr(ob, self._onend, None)
getDataMgr = getattr(ob, 'getDataMgr', None)
if getDataMgr is not None:
if callable(getDataMgr):
d = getDataMgr()
if d != last:
mgr = self.aq_parent.unrestrictedTraverse(d)
last = d
if callable(f): f(mgr)
for k, v in list(index.items()):
if v is b: del index[k]
b.clear()
def _show(self):
""" debug method """
b,dump,now = self._getCurrentBucket(1)
ringdumps = map(lambda x: `x[1]`[-4:], self._ring)
t = (
"now: "+`now`[-4:],
"dump_after: "+`dump`[-4:],
"ring_dumps: "+`ringdumps`,
"ring: " + `self._ring`
)
for x in t:
print x
def __setitem__(self, k, v):
current = self._getCurrentBucket()
index = self._ring._index
b = index.get(k)
if b is None:
# this is a new key
index[k] = current
elif b is not current:
# this is an old key that isn't in the current bucket.
del b[k] # delete it from the old bucket
index[k] = current
# change the value
current[k] = v
def __getitem__(self, k):
current = self._getCurrentBucket()
index = self._ring._index
# the next line will raise the proper error if the item has expired
b = index[k]
v = b[k] # grab the value before we potentially time it out.
if b is not current:
# it's not optimal to do writes in getitem, but there's no choice.
# we accessed the object, so it should become current.
index[k] = current # change the index to the current bucket.
current[k] = v # add the value to the current bucket.
del b[k] # delete the item from the old bucket.
return v
def get(self, k, default=_marker):
try: v = self[k]
except KeyError: v = _marker
if v is _marker:
if default is _marker:
return None
else:
return default
return v
def __delitem__(self, k):
self._getCurrentBucket()
index = self._ring._index
b = index[k]
del index[k]
del b[k]
def __len__(self):
self._getCurrentBucket()
return len(self._ring._index)
def has_key(self, k):
self._getCurrentBucket()
index = self._ring._index
return index.get(k, _marker) is not _marker
def values(self):
return map(lambda k, self=self: self[k], self.keys())
def items(self):
return map(lambda k, self=self: (k, self[k]), self.keys())
def keys(self):
self._getCurrentBucket()
index = self._ring._index
return map(lambda x: x, index.keys())
def update(self):
raise "Unsupported"
def clear(self):
raise "Unsupported"
def copy(self):
raise "Unsupported"
getLen = __len__
class Ring(Persistent):
""" Instances of this class will be frequently written to the ZODB,
so it's optimized as best possible for write-friendliness """
def __init__(self, l, index):
if not len(l):
raise "ring must have at least one element"
self._data = l
self._index = index
def __repr__(self):
return repr(self._data)
def __len__(self):
return len(self._data)
def __getitem__(self, i):
return self._data[i]
def turn(self):
last = self._data.pop(-1)
self._data.insert(0, last)
self._p_changed = 1
def _p_independent(self):
return 1
class PersistentAutoExpireMapping(AutoExpireMapping, Persistent,
Acquisition.Explicit):
""" Used by SessionFanout """
pass
=== Added File Zope/lib/python/Products/CoreSessionTracking/CHANGES.txt ===
Release 0.8
- Release 0.8 is incompatible with prior releases due mostly to changing
of persistent variable names and data structures and the author's
lack of available resources to write a conversion routine.
- Added onStart/onEnd events.
- Improved documentation.
- Fixed bug reported by Randy Kern in SessionData __setitem__.
- Overhauled session data object expiration. This fixed a number of
problems related to session data objects disappearing unexpectedly
and sticking around for longer than expected.
- Fixed bug in SessionFanout __getitem__.
- Added app-level conflict resolution for SessionData objects (only
works under 2.3.1 or better). On average, out of 10,000 requests
simultaneously handled by 7 threads, there will be fewer than 60
conflicts, which can usually be resolved readily by Zope's
automatic request-retry feature.
Release 0.7
- Added callback handler to close connections properly to handle
kid-clicking for mounted RAM-based storages. Thanks to Randall Kern
for finding and reporting this problem.
Release 0.6
- Moved all dtml files back to Product root dir because pre-2.3
Zopes can't handle a dtml directory.
- Fixed SessionStorage bug that could cause transaction errors.
- Changed icons.
Release 0.5
- Use a "SessionFanout" in lieu of having a BTree implementation which
is not as susceptible to ConflictErrors. This will need to go away
when a BTree implementation exists that isn't so susceptible.
- Did some module name changing
- Moved dtml files to a subdirectory
- Created SessionStorage, which is a packless RAM-based storage
for internal session data containers. Session Data Managers now
use a SessionStorage for internal data containers.
- Added an import/export facility to session data containers.
- Made session data objects into full mappings.
- Changed logic of AutoExpireMapping to time objects out faster.
- Changed token composition so that random portion leads. Token is
composed of 8-char str rep of random integer + 11 char base64
encoded timestamp for a total of 19 chars.
Release 0.4
- Cleaned up docs and interfaces after r03.
Release 0.3 (Publically unreleased version)
- Provided a management interface for the internal data container of
session data managers.
- Implemented AutoExpireMapping, which session data containers use as
a base class. Objects added to session data containers expire
automatically using inline garbage collection. Removed sessiongc.py
from the distribution as a result.
- Gave session data containers the responsibility for expiring
session data objects (it had been the responsibility of session data
managers).
- Implemented Session Data Container as subobject of mounted
MappingStorage (it had been implemented as a TransactionalMapping).
There is now a new class "SessionDataContainerMount" which
represents a mountpoint that is used for the in-memory
MappingStorage when an external data container is not used.
Release 0.2
- Removed dependency on Interface module to allow package to work with
Zopes which don't have them (like 2.2.3 and 2.2.4).
- Did some interface rearranging.
- Slightly improved documentation.
Initial Release (0.1)
Initial
=== Added File Zope/lib/python/Products/CoreSessionTracking/README.txt ===
Introduction
This is a development release of the Zope Core Session Tracking
implementation. The software allows you to associate "data objects"
with anonymous Zope visitors, allowing you to keep state about an
anonymous user between requests.
As this is a development release, the API will likely change in a
final release. More general information about the design is
available from
http://dev.zope.org/Wikis/DevSite/Projects/CoreSesssionTracking/FrontPage.
Features
Core Session Tracking key features:
- RAM-based storage of session data for modest requirements.
- The storage of session data as a set of persistent Zope objects
to allow the sessioning implementation to work with a cluster of
Zope Enterprise Objects (ZEO) servers.
- Interface-based API. This means it's possible to implement
alternate session data managers against things like SQL
databases or filesystem stores. The separation of the duties
between a "session id manager" a "session data manager", and
a "session data container" in the design makes the implementation
extensible.
- Use of cookies or form variables to pass sessioning information.
- Secure cookie support.
For installation and usage instructions, see help/CoreSessionTracking.stx.
=== Added File Zope/lib/python/Products/CoreSessionTracking/SessionData.py ===
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""
Core session tracking SessionData class.
$Id: SessionData.py,v 1.1.2.1 2001/10/04 19:32:27 matt Exp $
"""
__version__='$Revision: 1.1.2.1 $'[11:-2]
import time, sys
import Globals
from Persistence import Persistent
import Acquisition
from zLOG import LOG
import ExtensionClass
try:
from SessioningInterfaces import SessionDataInterface
except:
# pre-2.3 Zopes don't have an interfaces module
class SessionDataInterface:
pass
_marker = []
class SessionData(Persistent, Acquisition.Explicit):
""" simple session data object """
__allow_access_to_unprotected_subobjects__ = 1
__implements__ = SessionDataInterface
def __init__(self, id, onstart=None, onend=None, datamgr=None,
time=time.time):
self.id = id
self._datamgr = datamgr
self._container = {}
self._created = self._last_accessed = time()
self._onend = onend
self._onend_called = 0
self._onstart = onstart
self._onstart_called = 0
def getDataMgr(self):
return self._datamgr
def onStart(self, sdm):
if self._onstart and not self._onstart_called:
onstart = self._onstart.__of__(sdm)
onstart(self)
self._onstart_called = 1
def onEnd(self, sdm):
if self._onend and not self._onend_called:
onend = self._onend.__of__(sdm)
onend(self)
self._onend_called = 1
def __getitem__(self, k):
return self._container[k]
def __setitem__(self, k, v):
# if the key or value is a persistent instance,
# set up its _p_jar immediately
if hasattr(v, '_p_jar') and v._p_jar is None:
v._p_jar = self._p_jar
v._p_changed = 1
if hasattr(k, '_p_jar') and k._p_jar is None:
k._p_jar = self._p_jar
k._p_changed = 1
self._container[k] = v
self._p_changed = 1
set = __setitem__
def __len__(self):
return len(self._container)
def keys(self):
return self._container.keys()
def items(self):
return self._container.items()
def values(self):
return self._container.values()
def get(self, k, default=None):
return self._container.get(k, default)
def has_key(self, k, marker=_marker):
if self._container.get(k, marker) is not _marker: return 1
def delete(self, k):
del self._container[k]
self._p_changed = 1
def getId(self):
return self.id
def clear(self):
self._container.clear()
self._p_changed = 1
def update(self, d):
for k in d.keys():
self[k] = d[k]
def copy(self):
return self._container.copy()
def getCreated(self):
return self._created
def getLastAccessed(self):
return self._last_accessed
def setLastAccessed(self, time=time.time):
self._last_accessed = time()
def invalidate(self):
if hasattr(self, 'aq_parent'):
self.onEnd(self.aq_parent)
self._invalid = None
def __repr__(self):
return `self._container`
def _p_independent(self):
# My state doesn't depend on or materially effect the state of
# other objects.
return 1
Globals.default__class_init__(SessionData)
=== Added File Zope/lib/python/Products/CoreSessionTracking/SessionDataContainer.py ===
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""
Session data container
$Id: SessionDataContainer.py,v 1.1.2.1 2001/10/04 19:32:27 matt Exp $
"""
__version__='$Revision: 1.1.2.1 $'[11:-2]
import Globals
from Globals import HTMLFile, MessageDialog
from SessionStorage import SessionStorage
from ZODB.DB import DB
from Persistence import Persistent, PersistentMapping
from Acquisition import Implicit
from OFS.SimpleItem import SimpleItem
import threading, os
lock = threading.Lock()
del threading
try:
# Zope 2.3.1 and up
from BTrees import OOBTree
ctype = OOBTree.OOBTree
del OOBTree
from AutoExpireMapping import AutoExpireMapping
SessionContainer = AutoExpireMapping
del AutoExpireMapping
except ImportError:
# Zopes 2.3.0 and under
import BTree
ctype = BTree.BTree
del BTree
from SessionFanout import SessionFanout
SessionContainer = SessionFanout
del SessionFanout
try:
from SessioningInterfaces import SessionDataContainerInterface
except:
# pre-2.3 Zopes don't have Interfaces module
class SessionDataContainerInterface:
pass
# dbs is mapping of path to in-memory ZODB dbs which hold session data
# containers
dbs = {}
constructSessionDataContainerForm = HTMLFile('addExtDataContainer',
globals())
def constructSessionDataContainer(self, id, title='',timeout_mins=20,
REQUEST=None):
""" """
ob = SessionDataContainer(id, title, timeout_mins)
self._setObject(id, ob)
if REQUEST is not None:
return self.manage_main(self, REQUEST, update_menu=1)
class SessionDataContainerErr(Exception): pass
class SessionDataContainer(SimpleItem, SessionContainer):
""" """
meta_type = 'Session Data Container'
icon='misc_/CoreSessionTracking/datacontainer.gif'
__implements__ = SessionDataContainerInterface
manage_options=(
{'label': 'Manage', 'action':'manage_container'},
{'label': 'Security', 'action':'manage_access'},
{'label': 'Advanced', 'action':'manage_advanced'}
)
__ac_permissions__=(
('Access session data',
['get', 'set', 'has_key', 'getLen'],
['Anonymous', 'Manager']),
('View management screens',
['manage_container', 'manage_access', 'manage_advanced',
'getTimeoutMinutes'],
['Manager']),
('Manage Session Data Container',
['setTimeoutMinutes', 'setTitle','manage_changeSessionDataContainer',
'manage_importSessionData', 'manage_exportSessionData'],
['Manager']),
)
def __init__(self, id, title='', timeout_mins=20, ctype=ctype,
onend='onEnd', err_margin=.20):
SessionDataContainer.inheritedAttribute('__init__')(
self, timeout_mins, ctype, onend, err_margin
)
self.id = id
self.setTitle(title)
self.setTimeoutMinutes(timeout_mins)
def set(self, k, v):
""" """
self[k] = v
def __len__(self):
return self.getLen()
manage_container = HTMLFile('manageExtDataContainer',globals())
manage_advanced = HTMLFile('manageImpExpSessionData', globals())
def manage_changeSessionDataContainer(
self, title, timeout_mins, REQUEST=None
):
""" """
self.setTitle(title)
self.setTimeoutMinutes(timeout_mins)
if REQUEST is not None:
return self.manage_container(self, REQUEST)
def manage_exportSessionData(self, REQUEST=None):
""" """
f = os.path.join(Globals.data_dir, 'sessiondata.zexp')
self.c = PersistentMapping()
for k, v in self.items():
self.c[k] = v
get_transaction().commit()
self.c._p_jar.exportFile(self.c._p_oid, f)
del self.c
if REQUEST is not None:
return MessageDialog(title='Session data exported',
message='Session data exported to %s' % f,
action='manage_container')
def manage_importSessionData(self, REQUEST=None):
""" """
f = os.path.join(Globals.data_dir, 'sessiondata.zexp')
conn = self._p_jar
ob = conn.importFile(f)
for k, v in ob.items():
self[k] = v
if REQUEST is not None:
return MessageDialog(title='Session data imported',
message='Session data imported from %s' %f,
action='manage_container')
def setTitle(self, title):
if not title:
self.title = ''
else:
self.title = str(title)
def getTimeoutMinutes(self):
""" """
return SessionDataContainer.inheritedAttribute('getTimeoutMinutes')(
self
)
def setTimeoutMinutes(self, timeout_mins):
""" """
if timeout_mins != self.getTimeoutMinutes():
# order of calling is important!
self._setTimeout(timeout_mins)
self._reset()
def getSessionDataContainer(self):
return self
class SessionDataContainerMount(Persistent, Implicit):
"""
Singleton in-RAM SessionStorage mounted database which returns a
SessionDataContainer as its single interesting object
"""
def __init__(self):
self._clear()
def __setstate__(self, state):
self._clear()
def _clear(self):
self._v_db = None
self._v_conn = None
self._v_parentpath = None
self._v_dc_timeout = None
def __of__(self, parent):
parentpath = self._v_parentpath
if parentpath is None:
parentpath = self._v_parentpath = parent.getPhysicalPath()
timeout = self._v_dc_timeout
if timeout is None:
timeout = self._v_timeout = parent.internal_dc_timeout
return self._getContainer(parent, timeout).__of__(parent)
def _getDB(self, parentpath):
self._v_db = dbs.get(parentpath, None)
if self._v_db is None:
lock.acquire()
try:
s = SessionStorage()
dbs[parentpath] = self._v_db = DB(s)
finally:
lock.release()
return self._v_db
def _getConnection(self, parent):
db = self._v_db
if db is None:
db = self._getDB(self._v_parentpath)
conn = self._v_conn
if conn is None:
conn = self._v_conn = db.open() # no versioning
# if we don't have a jar yet, we steal our parent's
jar = self._p_jar or parent._p_jar
jar.onCloseCallback(ConnectionCloser(self, conn))
return conn
def _getContainer(self, parent, timeout):
conn = self._getConnection(parent)
root = conn.root()
container = root.get('container', None)
if container is None:
root['container'] = SessionDataContainer(
id='internal', timeout_mins=timeout
)
return root['container']
def __del__(self):
lock.acquire()
try:
try:
dbs[self._v_parentpath] = None # in case of circ refs
del dbs[self._v_parentpath]
except:
pass
finally:
lock.release()
class ConnectionCloser:
def __init__(self, mount, conn):
self.mount = mount
self.conn = conn
def __call__(self):
""" This is called by the 'parent' connection's onCloseCallback
handler, so that our 'spawned' connection will be closed when
our parent connection is closed. """
self.mount._v_conn = None
self.conn.close()
Globals.default__class_init__(SessionDataContainer)
Globals.default__class_init__(SessionDataContainerMount)
=== Added File Zope/lib/python/Products/CoreSessionTracking/SessionDataManager.py === (425/525 lines abridged)
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
[-=- -=- -=- 425 lines omitted -=- -=- -=-]
references to functions across ZODB databases.
"""
def __init__(self, fpath, ufolderpath=None, uid=None):
self.f = fpath
self.ufolder = ufolderpath
self.uid = uid
def __call__(self, sdo):
""" This should never fail with an exception """
user_changed = 0
try:
try:
try:
f = self.unrestrictedTraverse(self.f)
except:
fpath = string.join(self.f, '/')
raise SessionDataManagerErr, (
'the session event function named %s could not be '
'found in the ZODB' % fpath
)
if self.ufolder is not None:
user = getSecurityManager().getUser()
ufolder = self.unrestrictedTraverse(self.ufolder)
u = ufolder.getUser(self.uid)
u = getattr(u, 'aq_base', u)
u = u.__of__(ufolder)
user_changed = 1
newSecurityManager(None, u) # switch to saved user
try:
f(sdo)
except:
if hasattr(f, 'id'):
if callable(f.id): id = f.id()
else: id = f.id
else:
id = None
LOG('Session Tracking',WARNING,'session event failed',
'The call to function %s failed. Traceback:\n'
% id, sys.exc_info())
except:
LOG('Session Tracking', WARNING, 'session event failed',
'Uncaught error\n', sys.exc_info())
finally:
if user_changed:
# switch back to the original user
newSecurityManager(None, user)
Globals.default__class_init__(SessionDataManager)
Globals.default__class_init__(EventWrapper)
=== Added File Zope/lib/python/Products/CoreSessionTracking/SessionFanout.py ===
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""
Session fanout in lieu of a new BTree implementation. This is lame and should
definitely go away after a new BTree implementation is finished.
$Id: SessionFanout.py,v 1.1.2.1 2001/10/04 19:32:27 matt Exp $
"""
__version__ = '$Revision: 1.1.2.1 $'[11:-2]
from AutoExpireMapping import PersistentAutoExpireMapping
from Persistence import Persistent
import Acquisition
_marker = []
allowed_hashes = map(lambda x: "%02i" % x, range(0, 100))
class SessionFanout:
"""
Pure mixin.
A mapping which stores its items in a number of separate data structures
in order to reduce the probability of conflict in high-write situations.
Keys must be strings or integers. If keys are strings, the first
two characters of the key must be digits.
"""
def __init__(self, timeout_mins=20, ctype=None, onend='onEnd',
err_margin=.20):
self._initleaves(timeout_mins, ctype, onend, err_margin)
self._timeout_secs = timeout_mins * 60
self._ctype = ctype
self._onend = onend
self._err_margin = err_margin
def _setTimeout(self, timeout_mins):
for leaf in self._root:
leaf = leaf.__of__(self)
leaf._setTimeout(timeout_mins)
self._timeout_secs = timeout_mins * 60
def getTimeoutMinutes(self):
""" """
return self._timeout_secs / 60
def _reset(self):
for leaf in self._root:
leaf = leaf.__of__(self)
leaf._reset()
def _initleaves(self, timeout_mins, ctype, onend, err_margin):
self._root = []
for x in range(0,100):
m=PersistentAutoExpireMapping(timeout_mins,ctype,onend,err_margin)
self._root.append(m)
def _getleaf(self, key, allowed_hashes=allowed_hashes):
if key is not None:
if type(key) is not type(''):
key = `key`
if key[:2] in allowed_hashes:
lkey = int(key[:2])
leaf = self._root[lkey]
return leaf.__of__(self)
raise 'First two elements in key must be digits'
else:
return {}
def __delitem__(self, key):
leaf = self._getleaf(key)
del leaf[key]
def __getitem__(self, key):
leaf = self._getleaf(key)
return leaf[key]
def __len__(self):
l = 0
for leaf in self._root:
leaf = leaf.__of__(self)
l = l + len(leaf)
return l
getLen = __len__
# something is screwing up the inheritance of __len__ here, getLen
# is a workaround
def __setitem__(self, key, v):
leaf = self._getleaf(key)
leaf[key] = v
def copy(self):
raise 'Unsupported'
def get(self, key, default=_marker):
leaf = self._getleaf(key)
if default is _marker:
return leaf.get(key)
else:
return leaf.get(key, default)
def has_key(self, key):
leaf = self._getleaf(key)
return leaf.has_key(key)
def items(self):
items = []
for leaf in self._root:
leaf = leaf.__of__(self)
leafitems = map(lambda k,d=leaf: (k, d[k]), leaf.keys())
items.extend(leafitems)
items.sort()
return items
def keys(self):
keys = []
for leaf in self._root:
leaf = leaf.__of__(self)
keys.extend(map(lambda k: k, leaf.keys()))
keys.sort()
return keys
def update(self, b):
raise 'Unsupported'
def values(self):
values = []
for leaf in self._root:
leaf = leaf.__of__(self)
values.extend(map(lambda k: k, leaf.values()))
values.sort()
return values
=== Added File Zope/lib/python/Products/CoreSessionTracking/SessionIdManager.py === (458/558 lines abridged)
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
[-=- -=- -=- 458 lines omitted -=- -=- -=-]
TimeStamp=TimeStamp.TimeStamp, translate=string.translate
):
t=time()
ts=split(b2a(`apply(TimeStamp,(gmtime(t)[:5]+(t%60,)))`)[:-1],'=')[0]
return translate(ts, b64_trans)
def _getB64TStampToInt(
self, ts, TimeStamp=TimeStamp.TimeStamp, b64_untrans=b64_untrans,
a2b=binascii.a2b_base64, translate=string.translate
):
return TimeStamp(a2b(translate(ts+'=',b64_untrans))).timeTime()
def _getTokenPieces(self, token):
""" returns session token parts in a tuple consisting of rand_id,
timestamp
"""
return (token[:8], token[8:19])
def _isAWellFormedToken(self, token, binerr=binascii.Error,
timestamperr=TimeStamp.error):
try:
rnd, ts = self._getTokenPieces(token)
int(rnd)
self._getB64TStampToInt(ts)
return token
except (TypeError, ValueError, AttributeError, IndexError, binerr,
timestamperr):
return None
def _setId(self, id):
if id != self.id:
raise Globals.MessageDialog(
title='Cannot rename',
message='You cannot rename a session id manager, sorry!',
action ='./manage_main',)
Globals.default__class_init__(SessionIdManager)
=== Added File Zope/lib/python/Products/CoreSessionTracking/SessionStorage.py ===
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""
A storage implementation which uses RAM to persist objects, much like
MappingStorage, but unlike MappingStorage needs not be packed to get rid of
non-cyclic garbage. This is a ripoff of Jim's Packless bsddb3 storage.
$Id: SessionStorage.py,v 1.1.2.1 2001/10/04 19:32:27 matt Exp $
"""
__version__ ='$Revision: 1.1.2.1 $'[11:-2]
from struct import pack, unpack
from ZODB.referencesf import referencesf
from ZODB import POSException
from ZODB.BaseStorage import BaseStorage
class ReferenceCountError(POSException.POSError):
""" An error occured while decrementing a reference to an object in
the commit phase. The object's reference count was below zero."""
class SessionStorageError(POSException.POSError):
""" A Session Storage exception occurred. This probably indicates that
there is a low memory condition or a tempfile space shortage. Check
available tempfile space and RAM consumption and restart the server
process."""
class SessionStorage(BaseStorage):
def __init__(self, name='SessionStorage'):
"""
index -- mapping of oid to current serial
referenceCount -- mapping of oid to count
oreferences -- mapping of oid to a sequence of its referenced oids
opickle -- mapping of oid to pickle
"""
BaseStorage.__init__(self, name)
self._index={}
self._referenceCount={}
self._oreferences={}
self._opickle={}
self._tmp = []
self._oid = '\0\0\0\0\0\0\0\0'
def __len__(self):
return len(self._index)
## def new_oid(self, last=None):
## return BaseStorage.new_oid(self, last)
def getSize(self):
return 0
def _clear_temp(self):
self._tmp = []
def close(self):
"""
Close the storage
"""
def load(self, oid, version):
self._lock_acquire()
try:
try:
s=self._index[oid]
p=self._opickle[oid]
return p, s # pickle, serial
except:
raise SessionStorageError, (
"%s (%s)" % (SessionStorageError.__doc__, `oid`)
)
finally:
self._lock_release()
def store(self, oid, serial, data, version, transaction):
if transaction is not self._transaction:
raise POSException.StorageTransactionError(self, transaction)
if version:
raise POSException.Unsupported, "Versions aren't supported"
self._lock_acquire()
try:
if self._index.has_key(oid):
oserial=self._index[oid]
if serial != oserial: raise POSException.ConflictError
serial=self._serial
self._tmp.append((oid, data))
return serial
finally:
self._lock_release()
def _finish(self, tid, u, d, e):
zeros={}
referenceCount=self._referenceCount
referenceCount_get=referenceCount.get
oreferences=self._oreferences
serial=self._serial
index=self._index
opickle=self._opickle
tmp=self._tmp
oidlen=8 # length in bytes of oid string rep
intlen=4 # length in bytes of struct.packed integer string rep
for entry in tmp:
oid, data = entry[:]
referencesl=[]
referencesf(data, referencesl)
references={}
for roid in referencesl: references[roid]=1
referenced=references.has_key
# Create refcnt
if not referenceCount_get(oid):
referenceCount[oid] = 0
zeros[oid]=1
# update stored references
roids = oreferences.get(oid)
if roids is not None:
for roid in roids:
if referenced(roid):
# still referenced, so no need to update
del references[roid]
else:
# Delete the stored ref, since we no longer
# have it
roids.remove(roid)
# decrement refcnt:
rc = referenceCount_get(roid)
rc=rc-1
if rc < 0:
# This should never happen
raise ReferenceCountError, (
"%s (Oid %s had refcount %s)" %
(ReferenceCountError.__doc__,`roid`,rc)
)
referenceCount[roid] = rc
if rc==0: zeros[roid]=1
# Now add any references that weren't already stored:
if oreferences.get(oid) is None:
oreferences[oid] = []
for roid in references.keys():
oreferences[oid].append(roid)
# Create/update refcnt
rc=referenceCount_get(roid)
if rc is None:
referenceCount[roid] = 1
elif rc==0:
try: del zeros[roid]
except: pass
referenceCount[roid] = rc+1
else:
referenceCount[roid] = rc+1
index[oid] = serial
opickle[oid] = data
if zeros:
for oid in zeros.keys():
if oid == '\0\0\0\0\0\0\0\0': continue
self._takeOutGarbage(oid)
self._tmp = []
def _takeOutGarbage(self, oid):
# take out the garbage.
referenceCount=self._referenceCount
referenceCount_get=referenceCount.get
del referenceCount[oid]
del self._opickle[oid]
del self._index[oid]
# Remove/decref references
roids = self._oreferences[oid]
while roids:
roid = roids.pop(0)
# decrement refcnt:
rc=referenceCount_get(roid)
if rc:
if rc < 0:
rce = ReferenceCountError
raise rce, (
"%s (Oid %s had refcount %s)" %
(rce.__doc__,`roid`,rc)
)
if rc==0: self._takeOutGarbage(roid)
else: referenceCount[roid] = rc
def pack(self, t, referencesf):
self._lock_acquire()
try:
rindex={}
referenced=rindex.has_key
rootl=['\0\0\0\0\0\0\0\0']
# mark referenced objects
while rootl:
oid=rootl.pop()
if referenced(oid): continue
p = self._opickle[oid]
referencesf(p, rootl)
rindex[oid] = None
# sweep unreferenced objects
for oid in self._index.keys():
if not referenced(oid):
self._takeOutGarbage(oid)
finally:
self._lock_release()
=== Added File Zope/lib/python/Products/CoreSessionTracking/SessioningInterfaces.py === (467/567 lines abridged)
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
[-=- -=- -=- 467 lines omitted -=- -=- -=-]
Permission required: Access session data
"""
def __len__(self):
"""
Returns number of items in container.
Permission required: Access session data
"""
def getLen(self):
"""
Returns number of items in container. Callable from TTW code.
Permission required: Access session data
"""
def __setitem__(self, key, v):
"""
Sets item in container with key 'key' and value 'v'
Permission required: Access session data
"""
def get(self, key, default=None):
"""
Returns value referred to by key or default if no value with key.
Permission required: Access session data
"""
def has_key(self, key):
"""
Returns true if container has key.
Permission required: Access session data
"""
def set(self, k, v):
"""
Set key k to value v.
Permission required: Access session data
"""
=== Added File Zope/lib/python/Products/CoreSessionTracking/TODO.txt ===
Post release-8:
- Test heavily with ZEO.
- Figure out how to default-instantiate a sessioning environment for
new Zopes.
- Figure out how to better integrate CST into Zope in an out-of-the-box
configuration.
- Solve "None has no attribute 'load'" errors when accessing a
mounted storage under load. If you see this error, please help!
- Put out-of-memory protection in.
=== Added File Zope/lib/python/Products/CoreSessionTracking/VERSION.txt ===
0.8
=== Added File Zope/lib/python/Products/CoreSessionTracking/__init__.py ===
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""
Core session tracking initialization routines
$Id: __init__.py,v 1.1.2.1 2001/10/04 19:32:27 matt Exp $
"""
import SessionIdManager, SessionDataManager, SessionDataContainer
def initialize(context):
context.registerClass(
SessionIdManager.SessionIdManager,
permission='Add Session Id Manager',
icon='www/idmgr.gif',
constructors=(SessionIdManager.constructSessionIdManagerForm,
SessionIdManager.constructSessionIdManager)
)
context.registerClass(
SessionDataManager.SessionDataManager,
permission='Add Session Data Manager',
icon='www/datamgr.gif',
constructors=(SessionDataManager.constructSessionDataManagerForm,
SessionDataManager.constructSessionDataManager)
)
context.registerClass(
SessionDataContainer.SessionDataContainer,
permission='Add External Session Data Container',
icon='www/datacontainer.gif',
constructors=(SessionDataContainer.constructSessionDataContainerForm,
SessionDataContainer.constructSessionDataContainer)
)
context.registerHelp()
=== Added File Zope/lib/python/Products/CoreSessionTracking/addDataManager.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Add Session Data Manager</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<H2>Add Session Data Manager</H2>
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
<FORM ACTION="constructSessionDataManager" METHOD="POST">
<em>Zope Session Data Managers objects keep track of your users' session data objects. Developers interact with a Session Data Manager in order to store and retrieve information during a user session. A Session Data Manager communicates with a Session Id Manager to determine the session information for the current user, and hands out Session Data Objects related to that user obtained from a Session Data Container. </em><br><br>
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Id</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Title</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>
Internal Session Data Container Object Timeout (in minutes)
</EM></STRONG>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="timeout_mins:int" SIZE="10" value="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>External Session Data Container Path (optional)<br></strong> (e.g. '/nonundo_db/session_data_container'.<br> leave blank in order to use default internal <br>ram-based session data container)</EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="path" SIZE="60" value="">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Session onStart method path (optional)<br></strong>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="onstart" SIZE="60" value="">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Session onEnd method path (optional)<br></strong>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="onend" SIZE="60" value="">
</TD>
</TR>
<tr>
</TR>
<TR>
<td align="left" valign="top">
<em><strong>REQUEST Session Name</strong> (what name session is stored in REQUEST as)</em>
</td>
<td align="left" valign="top">
<input type="text" name="requestSessionName" value="SESSION">
</td>
</TR>
<TR>
<TD>
</TD>
<TD> <BR><INPUT TYPE="SUBMIT" VALUE=" Add "> </TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
=== Added File Zope/lib/python/Products/CoreSessionTracking/addExtDataContainer.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Add External Session Data Container</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<H2>Add External Session Data Container</H2>
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
<FORM ACTION="constructSessionDataContainer" METHOD="POST">
<em>External Session Data Containers can be used in conjunction with Session Data Managers to hold Session Data Objects. Session Data Managers by default use a simple RAM-based "internal" Session Data Container. The use of an External Session Data Container is recommended when dealing with large and performance-intensive sites. They can store truly persistent session data (which lasts between Zope server restarts). External Session Data Containers are <b>required</b> when using Zope's sessioning features in conjunction with Zope Enterprise Objects (ZEO). It is recommended that External Session Data Containers be added to a non-undo ZODB database, as they are write-intensive.</em><br><br>
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Id</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Title</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Data object timeout in minutes</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="timeout_mins:int" SIZE="10" value="20">
</TD>
</TR>
<TR>
<TD>
</TD>
<TD> <BR><INPUT TYPE="SUBMIT" VALUE=" Add "> </TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
=== Added File Zope/lib/python/Products/CoreSessionTracking/addIdManager.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Add Session Id Manager</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<H2>Add Session Id Manager</H2>
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
<FORM ACTION="constructSessionIdManager" METHOD="POST">
<input type=hidden name="id" value="session_id_mgr">
<em>Zope Session Id Manager objects perform the task of setting and retrieving Zope session ids for remote users. They are used primarily by Session Data Manager objects. A Session Id Manager's 'id' must always be 'session_id_mgr' in order for it to be found by Session Data Managers.</em><br><br>
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Id</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<strong>This object's Zope id will be<br>
"session_id_mgr"</strong>
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Title</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Session Token Key</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="tokenkey" SIZE="20" value="_ZopeId">
</TD>
</TR>
<tr>
<td> </td>
</tr>
<th align="left"><strong><em>Token Key Search Namespaces</strong></em></th>
<th align="left"><strong><em>Priority (1 is highest)</strong></em></th>
<tr>
<th align=left>Cookies</th>
<td>
<table border=1>
<tr>
<td align=left>
<input type="radio" name="cookiepri:int" value="1" CHECKED> 1
</td>
<td align=left>
<input type="radio" name="cookiepri:int" value="2"> 2
</td>
<td align=left>
<input type="radio" name="cookiepri:int" value="0"> Off
</td>
</tr>
</table>
</td>
</tr>
<tr>
<th align=left>Form vars</th>
<td align=left>
<table border=1>
<tr>
<td align=left>
<input type="radio" name="formpri:int" value="1"> 1
</td>
<td align=left>
<input type="radio" name="formpri:int" value="2" CHECKED> 2
</td>
<td align=left>
<input type="radio" name="formpri:int" value="0"> Off
</td> </tr>
</table>
</td>
</tr>
<td> </td>
<tr>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Cookie Path <br></strong>(leave blank to provide no path info in the <br>session cookie)</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiepath" SIZE="20" value="/">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Cookie Domain<br></strong>(leave blank to send cookies without domain <br>info -- however, if cookie domain is not blank,<br> it must contain at least two dots)</EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiedomain" SIZE="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Cookie Lifetime In Days</STRONG><br> (0 means send cookies which last only for the<br>lifetime of the browser)</STRONG></EM>
</EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookielifedays:int" SIZE="20" value="0">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Only Send Cookie Over HTTPS</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="cookiesecure">
</TD>
</TR>
</TR> <TR> <TD></TD> <TD> <BR><INPUT TYPE="SUBMIT" VALUE=" Add ">
</TD> </TR> </TABLE> </FORM> </BODY> </HTML>
=== Added File Zope/lib/python/Products/CoreSessionTracking/manageDataManager.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Manage Session Data Manager</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<table>
<tr>
<td>
<H2>Manage Session Data Manager</H2>
</td>
<td width="40%">
</td>
<td align="right">
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
</td>
</tr>
</table>
<FORM ACTION="manage_changeSessionDataManager" METHOD="POST">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Title</strong></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="60" value="&dtml-title;">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>External Session Data Container Path <br></strong>(e.g. '/nonundo_db/session_data_container'. <br>leave blank in order to use default internal <br>ram-based session data container)</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="path" SIZE="60" value="&dtml-getSessionDataContainerPath;">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Session onStart method path<br></strong>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="onstart" SIZE="60" value="&dtml-getOnStartPath;">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Session onEnd method path<br></strong>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="onend" SIZE="60" value="&dtml-getOnEndPath;">
</TD>
</TR>
<TR>
<td align="left" valign="top">
<em><strong>REQUEST Session Name</strong> (what name session is stored in REQUEST as)</em>
</td>
<td align="left" valign="top">
<input type="text" name="requestSessionName" value="&dtml-getRequestSessionName;">
</td>
</TR>
</TR> <TR> <TD></TD> <TD> <BR><INPUT TYPE="SUBMIT" VALUE=" Change ">
</TD> </TR> </TABLE> </FORM> </BODY> </HTML>
=== Added File Zope/lib/python/Products/CoreSessionTracking/manageExtDataContainer.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>External Session Data Container</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<table>
<tr>
<td>
<H2>External Session Data Container</H2>
</td>
<td width="40%">
</td>
<td align="right">
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
</td>
</tr>
</table>
<table>
<form action="manage_changeSessionDataContainer" method="post">
<tr>
<td align="left" valign="top">
<font color="green">
<dtml-let l=getLen>
<dtml-if l>
<dtml-if "l == 1">1 item is in this session data container.
<dtml-else><dtml-var l> items are in this session data container.
</dtml-if>
<dtml-else>
There are no items in this session data container.
</dtml-if>
</dtml-let>
</font>
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td align="left" valign="top">
<em><strong>Title</em></strong>
</td>
<td align="left" valign="top">
<input type="text" name="title" size=20 value=&dtml-title;>
</td>
</tr>
<tr>
<td align="left" valign="top">
<em><strong>Data object timeout value in minutes</em></strong>
</td>
<td align="left" valign="top">
<input type="text" name="timeout_mins:int" size=10
value=&dtml-getTimeoutMinutes;>
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td align="center" valign="top">
<input type=submit name=submit value=" Change ">
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td align="left" valign="top">
<strong><font color="red">WARNING!</font></strong>
The data objects currently existing in this session data container<br>
will be deleted when the data object timeout is changed.
</td>
</tr>
</form>
</table>
=== Added File Zope/lib/python/Products/CoreSessionTracking/manageIdManager.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Session Id Manager Settings</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<H2>Session Id Manager Settings</H2>
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
<FORM ACTION="manage_changeSessionIdManager" METHOD="POST">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Session Id Mgr On</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="on"
<dtml-if isOn>CHECKED</dtml-if>>
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Title</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="30" value="<dtml-var title html_quote>">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Session Token Key</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="tokenkey" SIZE="20"
value="<dtml-var getTokenKey html_quote>">
</TD>
</TR>
<th align=left><strong><em>Token Key Search Namespaces</strong></em></th>
<th align=left><strong><em>Priority</strong></em> (1 is highest)</th>
<tr>
<th align=left>Cookies</th>
<td align=left>
<table border=1>
<tr>
<td align=left>
<input type="radio" name="cookiepri:int" value="1"
<dtml-if "getTokenKeyNamespaces().get(1, _.None) == 'cookies'">CHECKED</dtml-if>>1
</td>
<td align=left>
<input type="radio" name="cookiepri:int" value="2"
<dtml-if "getTokenKeyNamespaces().get(2, _.None) == 'cookies'">CHECKED</dtml-if>>2
</td>
<td align=left>
<input type="radio" name="cookiepri:int" value="0"
<dtml-if "'cookies' not in getTokenKeyNamespaces().values()">CHECKED</dtml-if>>Off
</td>
</tr>
</table>
</td>
</tr>
<tr>
<th align=left>Form vars</th>
<td align=left>
<table border=1>
<tr>
<td align=left>
<input type="radio" name="formpri:int" value="1"
<dtml-if "getTokenKeyNamespaces().get(1, _.None) == 'form'">CHECKED</dtml-if>>1
</td>
<td align=left>
<input type="radio" name="formpri:int" value="2"
<dtml-if "getTokenKeyNamespaces().get(2, _.None) == 'form'">CHECKED</dtml-if>>2
</td>
<td align=left>
<input type="radio" name="formpri:int" value="0"
<dtml-if "'form' not in getTokenKeyNamespaces().values()">CHECKED</dtml-if>>Off
</td>
</tr>
</table>
</td>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Cookie Path<br></strong>(leave blank to provide no path info in the <br>session cookie)</EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiepath" SIZE="20"
value="<dtml-var getCookiePath html_quote>">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Cookie Domain</strong><br>
(leave blank to send cookies without domain <br>info -- however, if cookie domain is not blank,<br> it must contain at least two dots)</EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiedomain" SIZE="20"
value="<dtml-var getCookieDomain html_quote>">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Cookie Lifetime In Days<br></strong>
(0 means send cookies which last only for the<br>lifetime of the browser)</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookielifedays:int" SIZE="20"
value="<dtml-var getCookieLifeDays html_quote>">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<EM><STRONG>Only Send Cookie Over HTTPS</STRONG></EM>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="cookiesecure"
<dtml-if getCookieSecure>CHECKED</dtml-if>>
</TD>
</TR>
<TR>
<TD></TD>
<TD><BR><INPUT TYPE="SUBMIT" VALUE=" Change "></TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
=== Added File Zope/lib/python/Products/CoreSessionTracking/manageImpExpSessionData.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Advanced</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<table>
<tr>
<td>
<H2>Advanced Session Data Container Options</H2>
</td>
<td width="40%">
</td>
<td align="right">
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
</td>
</tr>
</table>
<h3>Import/Export Session Data</h3>
<div>
Session data will be imported/exported to/from the file
'var/sessiondata.zexp' on your server's hard disk in your Zope
directory.
</div>
<br>
<table>
<tr>
<td align="left" valign="top">
<form action="manage_exportSessionData" method="post">
<input type=submit name=submit value="Export Session Data">
</form>
</td>
<td width="20%"> </td>
<td align="left" valign="top">
<form action="manage_importSessionData" method="post">
<input type=submit name=submit value="Import Session Data">
</form>
</td>
</tr>
</table>
</html>
=== Added File Zope/lib/python/Products/CoreSessionTracking/manageIntDataContainer.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Internal Session Data Container</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<table>
<tr>
<td>
<H2>Internal Session Data Container</H2>
</td>
<td width="40%">
</td>
<td align="right">
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
</td>
</tr>
</table>
<table>
<form action="manage_changeInternalDC" method="post">
<tr>
<td align="left" valign="top">
<font color="green">
<dtml-let l=getInternalDCLen>
<dtml-if l>
<dtml-if "l == 1">1 item is in this session data container.
<dtml-else><dtml-var l> items are in this session data container.
</dtml-if>
<dtml-else>
There are no items in this session data container.
</dtml-if>
</dtml-let>
</font>
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td align="left" valign="top">
<em><strong>Data object timeout value in minutes</em></strong>
</td>
<td align="left" valign="top">
<input type="text" name="timeout_mins:int" size=10
value=&dtml-getInternalDCTimeoutMins;>
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td align="center" valign="top">
<input type=submit name=submit value=" Change ">
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td align="left" valign="top">
<strong><font color="red">WARNING!</font></strong>
The data objects currently existing in this session data container<br>
will be deleted when the data object timeout is changed.
</td>
</tr>
</form>
</table>
=== Added File Zope/lib/python/Products/CoreSessionTracking/manageSessionData.dtml ===
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Manage Session Manager Data</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<table>
<tr>
<td>
<H2>Manage Session Manager Data</H2>
</td>
<td width="40%">
</td>
<td align="right">
<dtml-var "HelpSys.HelpButton('CoreSessionTracking.stx','CoreSessionTracking')">
</td>
</tr>
</table>
<FORM ACTION="manage_deleteInvalidSessionData" METHOD="POST">
<TABLE CELLSPACING="2">
<tr>
<td align="left" valign="top">
<font color="green">&dtml-getNumberOfValidSessionDataObjects; session data objects are valid out of a total of &dtml-getNumberOfSessionDataObjects; that are currently in the session data container <dtml-if getSessionDataContainerPath><strong>(session data objects are currently being stored in the external session data container at &dtml-getSessionDataContainerPath;)</strong><dtml-else><strong>(session data objects are currently being stored in a ram-based data object container internal to this session manager)</strong></dtml-if>.</font><br><br>
</td>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<STRONG>Delete <em>invalid</em> session data objects</STRONG>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="submit" NAME="go" value=" Delete Invalid ">
</TD>
</TR>
<tr>
<td> </td>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<STRONG>Delete <em>all</em> session data objects</STRONG>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="submit" NAME="deleteall" value=" Delete All ">
</TD>
</TR>
</table>
</form>