Commit b33bf1df authored by Hanno Schlichting's avatar Hanno Schlichting

Move Products.Sessions and Transience into new distribution.

parent db473745
......@@ -21,6 +21,9 @@ Features Added
Restructuring
+++++++++++++
- Create new `Products.Sessions` distribution including Products.Sessions
and Products.Transience code.
- Merge `Products.OFSP` project back in.
- Dropped dependency declarations for indirect dependencies:
......
......@@ -65,6 +65,7 @@ eggs =
Products.ExternalMethod
Products.MailHost
Products.PythonScripts
Products.Sessions
Products.SiteErrorLog
Products.StandardCacheManagers
Products.ZCatalog
......
......@@ -24,6 +24,7 @@ Products.BTreeFolder2 = git ${remotes:github}/Products.BTreeFolder2 pushurl=${re
Products.ExternalMethod = git ${remotes:github}/Products.ExternalMethod pushurl=${remotes:github_push}/Products.ExternalMethod
Products.MailHost = git ${remotes:github}/Products.MailHost pushurl=${remotes:github_push}/Products.MailHost
Products.PythonScripts = git ${remotes:github}/Products.PythonScripts pushurl=${remotes:github_push}/Products.PythonScripts
Products.Sessions = git ${remotes:github}/Products.Sessions.git pushurl=${remotes:github_push}/Products.Sessions
Products.SiteErrorLog = git ${remotes:github}/Products.SiteErrorLog pushurl=${remotes:github_push}/Products.SiteErrorLog
Products.StandardCacheManagers = git ${remotes:github}/Products.StandardCacheManagers pushurl=${remotes:github_push}/Products.StandardCacheManagers
Products.ZCatalog = git ${remotes:github}/Products.ZCatalog pushurl=${remotes:github_push}/Products.ZCatalog branch=master
......
This diff is collapsed.
This diff is collapsed.
############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
############################################################################
# BBB location for APIs now defined in Products.Sessions.interfaces
from Products.Sessions.interfaces import IBrowserIdManager
BrowserIdManagerInterface = IBrowserIdManager # BBB
from Products.Sessions.interfaces import ISessionDataManager
SessionDataManagerInterface = ISessionDataManager
from Products.Sessions.interfaces import SessionDataManagerErr
from Products.Sessions.interfaces import BrowserIdManagerErr
############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
############################################################################
CHANGE_DATAMGR_PERM = 'Change Session Data Manager'
MGMT_SCREEN_PERM = 'View management screens'
ACCESS_CONTENTS_PERM = 'Access contents information'
ACCESS_SESSIONDATA_PERM = 'Access session data'
ARBITRARY_SESSIONDATA_PERM = 'Access arbitrary user session data'
CHANGE_IDMGR_PERM = 'Change Browser Id Manager'
MANAGE_CONTAINER_PERM = 'Manage Session Data Container'
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
""" Session managemnt product initialization
"""
from Products.Sessions.interfaces import BrowserIdManagerErr #BBB
from Products.Sessions.interfaces import SessionDataManagerErr #BBB
def initialize(context):
import BrowserIdManager
import SessionDataManager
context.registerClass(
BrowserIdManager.BrowserIdManager,
permission=BrowserIdManager.ADD_BROWSER_ID_MANAGER_PERM,
constructors=(BrowserIdManager.constructBrowserIdManagerForm,
BrowserIdManager.constructBrowserIdManager)
)
context.registerClass(
SessionDataManager.SessionDataManager,
permission=SessionDataManager.ADD_SESSION_DATAMANAGER_PERM,
constructors=(SessionDataManager.constructSessionDataManagerForm,
SessionDataManager.constructSessionDataManager)
)
# do module security declarations so folks can use some of the
# module-level stuff in PythonScripts
#
# declare on behalf of Transience too, since ModuleSecurityInfo is too
# stupid for me to declare in two places without overwriting one set
# with the other. :-(
from AccessControl import ModuleSecurityInfo
security = ModuleSecurityInfo('Products')
security.declarePublic('Sessions')
security.declarePublic('Transience')
security = ModuleSecurityInfo('Products.Sessions.interfaces')
security.declareObjectPublic()
security.setDefaultAccess('allow')
security = ModuleSecurityInfo('Products.Transience')
security.declarePublic('MaxTransientObjectsExceeded')
#BBB for names which should be imported from Products.Sessions.interfaces
security = ModuleSecurityInfo('Products.Sessions')
security.declarePublic('BrowserIdManagerErr')
security.declarePublic('SessionDataManagerErr')
############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
############################################################################
import os
DEBUG = os.environ.get('CST_DEBUG', '')
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five">
<five:deprecatedManageAddDelete
class="Products.Sessions.BrowserIdManager.BrowserIdManager"/>
<five:deprecatedManageAddDelete
class="Products.Sessions.SessionDataManager.SessionDataManager"/>
</configure>
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Session Data Manager'
)">
<FORM ACTION="constructSessionDataManager" METHOD="POST">
<TABLE CELLSPACING="2">
<tr>
<div class="form-help">
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 Browser Id Manager to determine the session information
for the current user, and hands out Session Data Objects related to that
user.
</div>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Id
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Title
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Transient Object Container Path
</div>
<div class="form-help">e.g. '/temp_folder/session_data'.</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="path" SIZE="60" value="">
</TD>
</TR>
<tr>
<td align="LEFT" valign="TOP">
<div class="form-label">
Place SESSION in REQUEST object as
</div>
</td>
<td align="LEFT" valign="TOP">
<input class="form-element" type="TEXT" name="requestName"
value="SESSION">
</td>
</tr>
<tr>
</TR>
<TR>
<TD>
</TD>
<TD> <BR><INPUT class="form-element" TYPE="SUBMIT" VALUE=" Add "> </TD>
</TR>
</TABLE>
</FORM>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Browser Id Manager'
)">
<FORM ACTION="constructBrowserIdManager" METHOD="POST">
<TABLE CELLSPACING="2">
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<div class="form-help">
Zope Browser Id Manager objects allow Zope to differentiate between site
visitors by "tagging" each of their browsers with a unique identifier. This
is useful if you need to tell visitors apart from one another even if they do
not "log in" to your site. Browser Id Managers are generally used
by interacting with the Zope sessioning machinery.
</div>
</tr>
<tr>
<td>&nbsp;</td>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Id
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">This object's Zope id must be<br>
"browser_id_manager"
</div>
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Title
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Browser Id Name
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="idname" SIZE="20" value="_ZopeId">
</TD>
</TR>
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td>
<div align=left class="form-label">Look for Browser Id in</th>
</td>
<td>
<table border=0>
<tr>
<td align=left>
<input type="checkbox" name="location:list" value="cookies" CHECKED> Cookies
</td>
</tr>
<tr>
<td align=left>
<input type="checkbox" name="location:list" value="form" CHECKED> Forms and Query Strings
</td>
</tr>
<tr>
<td align=left>
<input type="checkbox" name="location:list" value="url"> URLs
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>&nbsp;</td>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Automatically Encode Zope-Generated<br>URLs With A Browser Id
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="auto_url_encoding" SIZE="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Cookie Path
</div>
<div class="form-help">
leave blank to provide no path info in the browser cookie
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiepath" SIZE="20" value="/">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Cookie Domain
</div>
<div class="form-help">
leave blank to send cookies without domain<br>
info -- however, if cookie domain is not blank,<br>
it must contain at least two dots
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiedomain" SIZE="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Cookie Lifetime In Days
</div>
<div class="form-help">
0 means send cookies which last only for the<br>
lifetime of the browser
</div>
</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">
<div class="form-label">
Only Send Cookie Over HTTPS
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="cookiesecure">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Make cookie not aviable from JavaScript
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="cookiehttponly">
</TD>
</TR>
</TR> <TR> <TD></TD> <TD>
<INPUT class="form-element" TYPE="SUBMIT" VALUE=" Add ">
</TD> </TR> </TABLE> </FORM>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _,
form_title='Manage Session Data Manager'
)">
<p class="form-help" colspan=2>
A Session Data Manager object is responsible for maintaining a
relationship between session data objects and Zope browser ids.
It is part of the Zope sessioning machinery. Programmers may
interact with a session data manager in order to obtain
information about session data, but will more often use the
REQUEST.SESSION object to do sessioning-related tasks.
</p>
<form action="manage_changeSDM" method="post">
<table cellspacing="2">
<tr>
<td align="left" valign="top">
<div class="form-label">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="60" value="&dtml-title;">
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Transient Object Container Path
</div>
<div class="form-help">
e.g. '/temp_folder/session_data'
</div>
</td>
<td align="left" valign="top">
<input type="text" name="path" size="60"
value="&dtml-getContainerPath;">
</td>
</tr>
<tr>
<td align="LEFT" valign="TOP">
<div class="form-label">
Place SESSION in REQUEST object as
</div>
</td>
<td align="LEFT" valign="TOP">
<input class="form-element" type="TEXT" name="requestName"
value="&dtml-getRequestName;">
</td>
</tr>
<tr>
<td>
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" value = " Change ">
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _,
form_title='Manage Browser Id Manager'
)">
<FORM ACTION="manage_changeBrowserIdManager" METHOD="POST">
<p class="form-help">
Zope Browser Id Manager objects allow Zope to differentiate between site
visitors by "tagging" each of their browsers with a unique identifier. This
is useful if you need to tell visitors apart from one another even if they do
not "log in" to your site. Browser Id Managers are generally used
by interacting with the Zope sessioning machinery.
</p>
<TABLE CELLSPACING="2" border="0">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Title
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="30" value="&dtml-title;">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Browser Id Name
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="idname" SIZE="20" value="&dtml-getBrowserIdName;">
</TD>
</TR>
<dtml-let namespaces=getBrowserIdNamespaces>
<tr valign="top">
<td>
<div align=left class="form-label">Look for Browser Id in</th>
</td>
<td>
<table border=0>
<tr>
<td align=left>
<input type="checkbox" name="location:list" value="cookies"
<dtml-if "'cookies' in namespaces">CHECKED</dtml-if>> Cookies
</td>
</tr>
<tr>
<td align=left>
<input type="checkbox" name="location:list" value="form"
<dtml-if "'form' in namespaces">CHECKED</dtml-if>> Forms and Query Strings
</td>
</tr>
<tr>
<td align=left>
<input type="checkbox" name="location:list" value="url"
<dtml-if "'url' in namespaces">CHECKED</dtml-if>> URLs
</td>
</tr>
</table>
</td>
</tr>
</dtml-let>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Automatically Encode Zope-Generated<br>URLs With A Browser Id
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="auto_url_encoding"
<dtml-if getAutoUrlEncoding>CHECKED</dtml-if>>
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Cookie Path
</div>
<div class="form-help">
leave blank to provide no path info in the browser cookie
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiepath" SIZE="20"
value="&dtml-getCookiePath;">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Cookie Domain
</div>
<div class="form-help">
leave blank to send cookies without domain <br>
info -- however, if cookie domain is not blank,<br>
it must contain at least two dots
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookiedomain" SIZE="20"
value="&dtml-getCookieDomain;">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Cookie Lifetime In Days
</div>
<div class="form-help">
0 means send cookies which last only for the<br>
lifetime of the browser
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="cookielifedays:int" SIZE="20"
value="&dtml-getCookieLifeDays;">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Only Send Cookie Over HTTPS
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="cookiesecure"
<dtml-if getCookieSecure>CHECKED</dtml-if>>
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Make cookie not aviable from JavaScript
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="checkbox" NAME="cookiehttponly"
<dtml-if getCookieHTTPOnly>CHECKED</dtml-if>>
</TD>
</TR>
<TR>
<TD></TD>
<TD><BR><INPUT class="form-element" TYPE="SUBMIT" VALUE=" Change "></TD>
</TR>
</TABLE>
</FORM>
<dtml-var manage_page_footer>
############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
############################################################################
""" Session APIs
o See Also
- "Transient Object API":../../Transience/TransienceInterfaces.py
"""
from zope.interface import Interface
class IBrowserIdManager(Interface):
""" Zope Browser Id Manager interface.
A Zope Browser Id Manager is responsible for assigning ids to site
visitors, and for servicing requests from Session Data Managers
related to the browser id.
"""
def hasBrowserId():
""" Return true if there is a browser id for the current request.
o Permission required: Access contents information
o Does *not* raise an error if the request contains a broken
browser id.
"""
def getBrowserId(create=1):
""" Return a browser id for the current request.
o If create is false, return None if there is no browser id associated
with the current request.
o If create is true, return a newly-created browser id if
there is no browser id associated with the current request.
o This method is useful in conjunction with 'getBrowserIdName' if you
wish to embed the browser-id-name/browser-id combination as a hidden
value in a POST-based form.
o The browser id is opaque, has no business meaning, and its length,
type, and composition are subject to change.
o Permission required: Access contents information
o Raises BrowserIdManagerErr if an ill-formed browser id
is found in REQUEST.
"""
def getBrowserIdName():
"""
Returns a string with the name of the cookie/form variable which is
used by the current browser id manager as the name to look up when
attempting to obtain the browser id value. For example, '_ZopeId'.
Permission required: Access contents information
"""
def isBrowserIdNew():
"""
Returns true if browser id is 'new'. A browser id is 'new'
when it is first created and the client has therefore not sent it
back to the server in any request.
Permission required: Access contents information
Raises: BrowserIdManagerErr. If there is no current browser id.
"""
def isBrowserIdFromCookie():
""" Return true if browser id comes from a cookie.
o Permission required: Access contents information
o Raise BrowserIdManagerErr if there is no current browser id.
"""
def isBrowserIdFromForm():
""" Return true if browser id comes from a form variable.
o Variable may come from either the query string or a post.
o Permission required: Access contents information
o Raise BrowserIdManagerErr if there is no current browser id.
"""
def isBrowserIdFromUrl():
""" Return true if browser id comes from a cookie.
o Permission required: Access contents information
o Raise BrowserIdManagerErr if there is no current browser id.
"""
def flushBrowserIdCookie():
""" Deletes the browser id cookie from the client browser.
o Permission required: Access contents information
o Raise BrowserIdManagerErr if the 'cookies' namespace isn't
a browser id namespace.
"""
def setBrowserIdCookieByForce(bid):
""" Sets the browser id cookie to browser id 'bid' by force.
o Useful when you need to 'chain' browser id cookies across domains
for the same user (perhaps temporarily using query strings).
o Permission required: Access contents information
o Raise BrowserIdManagerErr if the 'cookies' namespace isn't
a browser id namespace.
"""
def getHiddenFormField():
""" Return a string usable as a hidden form field for the browser id.
o String is of the form::
<input type="hidden" name="_ZopeId" value="H7HJGYUFGFyHKH*" />
o name and the value represent the current browser id
name and current browser id.
"""
def encodeUrl(url, style='querystring'):
""" Encode a given URL with the current browser id.
o Two forms of URL-encoding are supported: 'querystring' and 'inline'.
o 'querystring' is the default.
o If the 'querystring' form is used, the browser id name/value pair
are postfixed onto the URL as a query string.
o If the 'inline' form is used, the browser id name/value pair
are prefixed onto the URL as the first two path segment elements.
o For example:
- The call encodeUrl('http://foo.com/amethod', style='querystring')
might return 'http://foo.com/amethod?_ZopeId=as9dfu0adfu0ad'.
- The call encodeUrl('http://foo.com/amethod, style='inline')
might return 'http://foo.com/_ZopeId/as9dfu0adfu0ad/amethod'.
o Permission required: Access contents information
o Raise BrowserIdManagerErr if there is no current browser id.
"""
class BrowserIdManagerErr(ValueError):
""" Error raised during some browser id manager operations
o See IBrowserIdManager methods.
o This exception may be caught in PythonScripts. A successful
import of the exception for PythonScript use would need to be::
from Products.Sessions.interfaces import BrowserIdManagerErr
"""
class ISessionDataManager(Interface):
""" Zope Session Data Manager interface.
A Zope Session Data Manager is responsible for maintaining Session
Data Objects, and for servicing requests from application code
related to Session Data Objects. It also communicates with a Browser
Id Manager to provide information about browser ids.
"""
def getBrowserIdManager():
""" Return the nearest acquirable browser id manager.
o Raise SessionDataManagerErr if no browser id manager can be found.
o Permission required: Access session data
"""
def getSessionData(create=1):
""" Return a Session Data Object for the current browser id.
o If there is no current browser id, and create is true,
return a new Session Data Object.
o If there is no current browser id and create is false, returns None.
o Permission required: Access session data
"""
def hasSessionData():
""" Does a Session Data Object exist for the current browser id?
o Do not create a Session Data Object if one does not exist.
o Permission required: Access session data
"""
def getSessionDataByKey(key):
""" Return a Session Data Object associated with 'key'.
o If there is no Session Data Object associated with 'key',
return None.
o Permission required: Access arbitrary user session data
"""
class SessionDataManagerErr(ValueError):
""" Error raised during some session data manager operations
o See ISesseionDataManager.
o This exception may be caught in PythonScripts. A successful
import of the exception for PythonScript use would need to be::
from Products.Sessions.interfaces import SessionDataManagerErr
"""
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import time
from Testing import makerequest
import ZODB # in order to get Persistence.Persistent working
import transaction
import Acquisition
from Products.Sessions.BrowserIdManager import BrowserIdManager, \
getNewBrowserId
from Products.Sessions.SessionDataManager import \
SessionDataManager
from Products.Transience.Transience import \
TransientObjectContainer
from Products.TemporaryFolder.TemporaryFolder import MountedTemporaryFolder
from ZODB.POSException import ConflictError, \
ReadConflictError, BTreesConflictError
from unittest import TestCase, TestSuite, makeSuite
import threading, random
from ZODB.DemoStorage import DemoStorage
from OFS.Application import Application
import traceback
from Products.Transience.tests import fauxtime
import Products.Transience.Transience
import Products.Transience.TransientObject
Products.Transience.Transience.time = fauxtime
Products.Transience.TransientObject.time = fauxtime
tf_name = 'temp_folder'
idmgr_name = 'browser_id_manager'
toc_name = 'temp_transient_container'
sdm_name = 'session_data_manager'
stuff = {}
def log_time():
"""Return a simple time string without spaces suitable for logging."""
return ("%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d"
% time.localtime()[:6])
def _getDB():
db = stuff.get('db')
if not db:
ds = DemoStorage()
db = ZODB.DB(ds)
conn = db.open()
root = conn.root()
app = Application()
root['Application']= app
_populate(app)
transaction.commit()
stuff['db'] = db
conn.close()
return db
def _delDB():
transaction.abort()
del stuff['db']
class Foo(Acquisition.Implicit): pass
def _populate(app):
bidmgr = BrowserIdManager(idmgr_name)
tf = MountedTemporaryFolder(tf_name, 'Temporary Folder')
toc = TransientObjectContainer(toc_name, title='Temporary '
'Transient Object Container', timeout_mins=1)
session_data_manager=SessionDataManager(id=sdm_name,
path='/'+tf_name+'/'+toc_name, title='Session Data Manager')
try: app._delObject(idmgr_name)
except AttributeError: pass
try: app._delObject(tf_name)
except AttributeError: pass
try: app._delObject(sdm_name)
except AttributeError: pass
app._setObject(idmgr_name, bidmgr)
app._setObject(sdm_name, session_data_manager)
app._setObject(tf_name, tf)
transaction.commit()
app.temp_folder._setObject(toc_name, toc)
transaction.commit()
class TestMultiThread(TestCase):
def testOverlappingBrowserIds(self):
token = getNewBrowserId()
self.go(token)
def testNonOverlappingBrowserIds(self):
token = None
self.go(token)
def go(self, token):
readers = []
writers = []
valuers = []
readiters = 3
writeiters = 3
valueiters = 3
numreaders = 2
numwriters = 4
numvaluers = 1
db = _getDB()
for i in range(numreaders):
thread = ReaderThread(db, readiters, token)
readers.append(thread)
for i in range(numvaluers):
thread = ValuesGetterThread(db, valueiters, token)
valuers.append(thread)
for i in range(numwriters):
thread = WriterThread(db, writeiters, token)
writers.append(thread)
for thread in readers:
thread.start()
time.sleep(0.1)
for thread in writers:
thread.start()
time.sleep(0.1)
for thread in valuers:
thread.start()
time.sleep(0.1)
active = threading.activeCount()
while active > 0:
active = threading.activeCount()-1
print 'waiting for %s threads' % active
print "readers: ", numActive(readers),
print "writers: ", numActive(writers),
print "valuers: ", numActive(valuers)
time.sleep(5)
def numActive(threads):
i = 0
for thread in threads:
if not thread.isFinished():
i+=1
return i
class BaseReaderWriter(threading.Thread):
def __init__(self, db, iters, token=None):
self.iters = iters
self.sdm_name = sdm_name
self.finished = 0
self.db = db
self.token = token
threading.Thread.__init__(self)
def run(self):
i = 0
try:
while 1:
self.conn = self.db.open()
self.app = self.conn.root()['Application']
self.app = makerequest.makerequest(self.app)
if self.token is None:
token = getNewBrowserId()
else:
token = self.token
self.app.REQUEST.browser_id_ = token
try:
self.run1()
return
except ReadConflictError:
#traceback.print_exc()
print "R",
except BTreesConflictError:
print "B",
except ConflictError:
print "W",
except:
transaction.abort()
print log_time()
traceback.print_exc()
raise
i = i + 1
transaction.abort()
self.conn.close()
time.sleep(random.randrange(10) * .1)
finally:
transaction.abort()
self.conn.close()
del self.app
self.finished = 1
print '%s finished' % self.__class__
def isFinished(self):
return self.finished
class ReaderThread(BaseReaderWriter):
def run1(self):
session_data_manager = getattr(self.app, self.sdm_name)
data = session_data_manager.getSessionData(create=1)
t = time.time()
data[t] = 1
transaction.commit()
for i in range(self.iters):
data = session_data_manager.getSessionData()
time.sleep(random.choice(range(3)))
transaction.commit()
class WriterThread(BaseReaderWriter):
def run1(self):
session_data_manager = getattr(self.app, self.sdm_name)
for i in range(self.iters):
data = session_data_manager.getSessionData()
data[time.time()] = 1
n = random.choice(range(3))
time.sleep(n)
if n % 2 == 0:
transaction.commit()
else:
transaction.abort()
class ValuesGetterThread(BaseReaderWriter):
def run1(self):
tf = getattr(self.app, tf_name)
toc = getattr(tf, toc_name)
for i in range(self.iters):
print '%s values in toc' % len(toc.values())
n = random.choice(range(3))
time.sleep(n)
if n % 2 == 0:
transaction.commit()
else:
transaction.abort()
def test_suite():
test_multithread = makeSuite(TestMultiThread, 'test')
suite = TestSuite((test_multithread,))
return suite
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
# This file is needed to make this a package.
This diff is collapsed.
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import unittest
tf_name = 'temp_folder'
idmgr_name = 'browser_id_manager'
toc_name = 'temp_transient_container'
sdm_name = 'session_data_manager'
stuff = {}
def _getDB():
from OFS.Application import Application
import transaction
db = stuff.get('db')
if not db:
from ZODB import DB
from ZODB.DemoStorage import DemoStorage
ds = DemoStorage()
db = DB(ds, pool_size=60)
conn = db.open()
root = conn.root()
app = Application()
root['Application']= app
transaction.savepoint(optimistic=True)
_populate(app)
stuff['db'] = db
conn.close()
return db
def _delDB():
import transaction
transaction.abort()
del stuff['db']
def _populate(app):
from OFS.DTMLMethod import DTMLMethod
from Products.Sessions.BrowserIdManager import BrowserIdManager
from Products.Sessions.SessionDataManager import SessionDataManager
from Products.TemporaryFolder.TemporaryFolder import MountedTemporaryFolder
from Products.Transience.Transience import TransientObjectContainer
import transaction
bidmgr = BrowserIdManager(idmgr_name)
tf = MountedTemporaryFolder(tf_name, title="Temporary Folder")
toc = TransientObjectContainer(toc_name, title='Temporary '
'Transient Object Container', timeout_mins=20)
session_data_manager=SessionDataManager(id=sdm_name,
path='/'+tf_name+'/'+toc_name, title='Session Data Manager',
requestName='TESTOFSESSION')
try:
app._delObject(idmgr_name)
except (AttributeError, KeyError):
pass
try:
app._delObject(tf_name)
except (AttributeError, KeyError):
pass
try:
app._delObject(sdm_name)
except (AttributeError, KeyError):
pass
try:
app._delObject('index_html')
except (AttributeError, KeyError):
pass
app._setObject(idmgr_name, bidmgr)
app._setObject(sdm_name, session_data_manager)
app._setObject(tf_name, tf)
transaction.commit()
app.temp_folder._setObject(toc_name, toc)
transaction.commit()
# index_html necessary for publishing emulation for testAutoReqPopulate
app._setObject('index_html', DTMLMethod('', __name__='foo'))
transaction.commit()
class TestSessionManager(unittest.TestCase):
def setUp(self):
from Testing import makerequest
db = _getDB()
conn = db.open()
root = conn.root()
self.app = makerequest.makerequest(root['Application'])
timeout = self.timeout = 1
def tearDown(self):
_delDB()
self.app._p_jar.close()
del self.app
def testHasId(self):
self.assertTrue(self.app.session_data_manager.id == \
sdm_name)
def testHasTitle(self):
self.assertTrue(self.app.session_data_manager.title \
== 'Session Data Manager')
def testGetSessionDataNoCreate(self):
sd = self.app.session_data_manager.getSessionData(0)
self.assertTrue(sd is None)
def testGetSessionDataCreate(self):
from Products.Transience.Transience import TransientObject
sd = self.app.session_data_manager.getSessionData(1)
self.assertTrue(sd.__class__ is TransientObject)
def testHasSessionData(self):
sd = self.app.session_data_manager.getSessionData()
self.assertTrue(self.app.session_data_manager.hasSessionData())
def testNotHasSessionData(self):
self.assertTrue(not self.app.session_data_manager.hasSessionData())
def testSessionDataWrappedInSDMandTOC(self):
from Acquisition import aq_base
sd = self.app.session_data_manager.getSessionData(1)
sdm = aq_base(getattr(self.app, sdm_name))
toc = aq_base(getattr(self.app.temp_folder, toc_name))
self.assertTrue(aq_base(sd.aq_parent) is sdm)
self.assertTrue(aq_base(sd.aq_parent.aq_parent) is toc)
def testNewSessionDataObjectIsValid(self):
from Acquisition import aq_base
from Products.Transience.Transience import TransientObject
sdType = type(TransientObject(1))
sd = self.app.session_data_manager.getSessionData()
self.assertTrue(type(aq_base(sd)) is sdType)
self.assertTrue(not hasattr(sd, '_invalid'))
def testBrowserIdIsSet(self):
sd = self.app.session_data_manager.getSessionData()
mgr = getattr(self.app, idmgr_name)
self.assertTrue(mgr.hasBrowserId())
def testGetSessionDataByKey(self):
sd = self.app.session_data_manager.getSessionData()
mgr = getattr(self.app, idmgr_name)
token = mgr.getBrowserId()
bykeysd = self.app.session_data_manager.getSessionDataByKey(token)
self.assertTrue(sd == bykeysd)
def testBadExternalSDCPath(self):
from Products.Sessions.SessionDataManager import SessionDataManagerErr
sdm = self.app.session_data_manager
# fake out webdav
sdm.REQUEST['REQUEST_METHOD'] = 'GET'
sdm.setContainerPath('/fudgeffoloo')
self.assertRaises(SessionDataManagerErr, self._testbadsdcpath)
def _testbadsdcpath(self):
self.app.session_data_manager.getSessionData()
def testInvalidateSessionDataObject(self):
sdm = self.app.session_data_manager
sd = sdm.getSessionData()
sd['test'] = 'Its alive! Alive!'
sd.invalidate()
self.assertTrue(not sdm.getSessionData().has_key('test'))
def testGhostUnghostSessionManager(self):
import transaction
sdm = self.app.session_data_manager
transaction.commit()
sd = sdm.getSessionData()
sd.set('foo', 'bar')
sdm._p_changed = None
transaction.commit()
self.assertTrue(sdm.getSessionData().get('foo') == 'bar')
def testSubcommitAssignsPJar(self):
global DummyPersistent # so pickle can find it
from Persistence import Persistent
import transaction
class DummyPersistent(Persistent):
pass
sd = self.app.session_data_manager.getSessionData()
dummy = DummyPersistent()
sd.set('dp', dummy)
self.assertTrue(sd['dp']._p_jar is None)
transaction.savepoint(optimistic=True)
self.assertFalse(sd['dp']._p_jar is None)
def testForeignObject(self):
from ZODB.POSException import InvalidObjectReference
self.assertRaises(InvalidObjectReference, self._foreignAdd)
def _foreignAdd(self):
import transaction
ob = self.app.session_data_manager
# we don't want to fail due to an acquisition wrapper
ob = ob.aq_base
# we want to fail for some other reason:
sd = self.app.session_data_manager.getSessionData()
sd.set('foo', ob)
transaction.commit()
def testAqWrappedObjectsFail(self):
from Acquisition import Implicit
import transaction
class DummyAqImplicit(Implicit):
pass
a = DummyAqImplicit()
b = DummyAqImplicit()
aq_wrapped = a.__of__(b)
sd = self.app.session_data_manager.getSessionData()
sd.set('foo', aq_wrapped)
self.assertRaises(TypeError, transaction.commit)
def testAutoReqPopulate(self):
self.app.REQUEST['PARENTS'] = [self.app]
self.app.REQUEST['URL'] = 'a'
self.app.REQUEST.traverse('/')
self.assertTrue(self.app.REQUEST.has_key('TESTOFSESSION'))
def testUnlazifyAutoPopulated(self):
from Acquisition import aq_base
from Products.Transience.Transience import TransientObject
self.app.REQUEST['PARENTS'] = [self.app]
self.app.REQUEST['URL'] = 'a'
self.app.REQUEST.traverse('/')
sess = self.app.REQUEST['TESTOFSESSION']
sdType = type(TransientObject(1))
self.assertTrue(type(aq_base(sess)) is sdType)
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestSessionManager),
))
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""
Module used for testing transience (BTree-API-conforming data structure)
"""
from Persistence.mapping import PersistentMapping
import sys
class FakeIOBTree(PersistentMapping):
def keys(self, min, max):
L = []
if min is None:
min = 0
if max is None:
max = sys.maxint
for k in self.data:
if min <= k <= max:
L.append(k)
return L
import time
class PreventTransactionCommit(Exception):
def __init__(self, reason):
self. reason = reason
def __str__(self):
return "Uncommittable transaction: " % self.reason
class UncommittableJar:
""" A jar that cannot be committed """
def __init__(self, reason):
self.reason = reason
self.time = time.time()
def sortKey(self):
return str(id(self))
def tpc_begin(self, *arg, **kw):
pass
def commit(self, obj, transaction):
pass
def tpc_vote(self, transaction):
raise PreventTransactionCommit(self.reason)
def abort(*args):
pass
class makeTransactionUncommittable:
"""
- register an uncommittable object with the provided transaction
which prevents the commit of that transaction
"""
def __init__(self, transaction, reason):
self._p_jar = UncommittableJar(reason)
transaction.register(self)
This diff is collapsed.
This diff is collapsed.
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Simple ZODB-based transient object implementation.
"""
import logging
import os
import random
import sys
import thread
import time
from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import Implicit
from Persistence import Persistent
from ZODB.POSException import ConflictError
from zope.interface import implements
from Products.Transience.TransienceInterfaces import DictionaryLike
from Products.Transience.TransienceInterfaces import \
ImmutablyValuedMappingOfPickleableObjects
from Products.Transience.TransienceInterfaces import ItemWithId
from Products.Transience.TransienceInterfaces import Transient
from Products.Transience.TransienceInterfaces import TransientItemContainer
from Products.Transience.TransienceInterfaces import TTWDictionary
DEBUG = int(os.environ.get('Z_TOC_DEBUG', 0))
LOG = logging.getLogger('Zope.TransientObject')
def TLOG(*args):
sargs = []
sargs.append(str(thread.get_ident()))
sargs.append(str(time.time()))
for arg in args:
sargs.append(str(arg))
msg = ' '.join(sargs)
LOG.info(msg)
_notfound = []
WRITEGRANULARITY=30 # Timing granularity for access write clustering, seconds
class TransientObject(Persistent, Implicit):
""" Dictionary-like object that supports additional methods
concerning expiration and containment in a transient object container
"""
implements(ItemWithId, # randomly generate an id
Transient,
DictionaryLike,
TTWDictionary,
ImmutablyValuedMappingOfPickleableObjects
)
security = ClassSecurityInfo()
security.setDefaultAccess('allow')
security.declareObjectPublic()
_last_modified = None
# _last modified indicates the last time that __setitem__, __delitem__,
# update or clear was called on us.
def __init__(self, containerkey):
self.token = containerkey
self.id = self._generateUniqueId()
self._container = {}
self._created = self._last_accessed = time.time()
# _last_accessed indicates the last time that *our container
# was asked about us* (NOT the last time __getitem__ or get
# or any of our other invariant data access methods are called).
# Our container manages our last accessed time, we don't much
# concern ourselves with it other than exposing an interface
# to set it on ourselves.
# -----------------------------------------------------------------
# ItemWithId
#
def getId(self):
return self.id
# -----------------------------------------------------------------
# Transient
#
def invalidate(self):
# hasattr hides conflicts
if getattr(self, '_invalid', _notfound) is not _notfound:
# we dont want to invalidate twice
return
trans_ob_container = None
# search our acquisition chain for a transient object container
# and delete ourselves from it.
for ob in getattr(self, 'aq_chain', []):
if TransientItemContainer.providedBy(ob):
trans_ob_container = ob
break
if trans_ob_container is not None:
if trans_ob_container.has_key(self.token):
del trans_ob_container[self.token]
self._invalid = None
def isValid(self):
# hasattr hides conflicts
if getattr(self, '_invalid', _notfound) is _notfound:
return 1
def getLastAccessed(self):
return self._last_accessed
def setLastAccessed(self):
# check to see if the last_accessed time is too recent, and avoid
# setting if so, to cut down on heavy writes
t = time.time()
if (self._last_accessed + WRITEGRANULARITY) < t:
self._last_accessed = t
def getLastModified(self):
return self._last_modified
def setLastModified(self):
self._last_modified = time.time()
def getCreated(self):
return self._created
def getContainerKey(self):
return self.token
# -----------------------------------------------------------------
# DictionaryLike
#
def keys(self):
return self._container.keys()
def values(self):
return self._container.values()
def items(self):
return self._container.items()
def get(self, k, default=_notfound):
v = self._container.get(k, default)
if v is _notfound: return None
return v
def has_key(self, k):
if self._container.get(k, _notfound) is not _notfound: return 1
return 0
def clear(self):
self._p_changed = 1
self._container.clear()
self.setLastModified()
def update(self, d):
self._p_changed = 1
for k in d.keys():
self[k] = d[k]
# -----------------------------------------------------------------
# ImmutablyValuedMappingOfPickleableObjects (what a mouthful!)
#
def __setitem__(self, k, v):
self._p_changed = 1
self._container[k] = v
self.setLastModified()
def __getitem__(self, k):
return self._container[k]
def __delitem__(self, k):
self._p_changed = 1
del self._container[k]
self.setLastModified()
# -----------------------------------------------------------------
# TTWDictionary
#
set = __setitem__
__guarded_setitem__ = __setitem__
__guarded_delitem__ = __delitem__
delete = __delitem__
# -----------------------------------------------------------------
# Other non interface code
#
def _p_resolveConflict(self, saved, state1, state2):
DEBUG and TLOG('entering TO _p_rc')
DEBUG and TLOG('states: sv: %s, s1: %s, s2: %s' % (
saved, state1, state2))
states = [saved, state1, state2]
# We can clearly resolve the conflict if one state is invalid,
# because it's a terminal state.
for state in states:
if state.has_key('_invalid'):
DEBUG and TLOG('TO _p_rc: a state was invalid')
return state
# The only other times we can clearly resolve the conflict is if
# the token, the id, or the creation time don't differ between
# the three states, so we check that here. If any differ, we punt
# by raising ConflictError.
attrs = ['token', 'id', '_created']
for attr in attrs:
svattr = saved.get(attr)
s1attr = state1.get(attr)
s2attr = state2.get(attr)
DEBUG and TLOG('TO _p_rc: attr %s: sv: %s s1: %s s2: %s' %
(attr, svattr, s1attr, s2attr))
if not svattr==s1attr==s2attr:
DEBUG and TLOG('TO _p_rc: cant resolve conflict')
raise ConflictError
# Now we need to do real work.
#
# Data in our _container dictionaries might conflict. To make
# things simple, we intentionally create a race condition where the
# state which was last modified "wins". It would be preferable to
# somehow merge our _containers together, but as there's no
# generally acceptable way to union their states, there's not much
# we can do about it if we want to be able to resolve this kind of
# conflict.
# We return the state which was most recently modified, if
# possible.
states.sort(lastmodified_sort)
if states[0].get('_last_modified'):
DEBUG and TLOG('TO _p_rc: returning last mod state')
return states[0]
# If we can't determine which object to return on the basis
# of last modification time (no state has been modified), we return
# the object that was most recently accessed (last pulled out of
# our parent). This will return an essentially arbitrary state if
# all last_accessed values are equal.
states.sort(lastaccessed_sort)
DEBUG and TLOG('TO _p_rc: returning last_accessed state')
return states[0]
getName = getId # this is for SQLSession compatibility
def _generateUniqueId(self):
t = str(int(time.time()))
d = "%010d" % random.randint(0, sys.maxint-1)
return "%s%s" % (t, d)
def __repr__(self):
return "id: %s, token: %s, content keys: %s" % (
self.id, self.token, `self.keys()`
)
def lastmodified_sort(d1, d2):
""" sort dictionaries in descending order based on last mod time """
m1 = d1.get('_last_modified', 0)
m2 = d2.get('_last_modified', 0)
if m1 == m2: return 0
if m1 > m2: return -1 # d1 is "less than" d2
return 1
def lastaccessed_sort(d1, d2):
""" sort dictionaries in descending order based on last access time """
m1 = d1.get('_last_accessed', 0)
m2 = d2.get('_last_accessed', 0)
if m1 == m2: return 0
if m1 > m2: return -1 # d1 is "less than" d2
return 1
InitializeClass(TransientObject)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""
Transience initialization routines
"""
import ZODB # this is to help out testrunner, don't remove.
import Transience
# import of MaxTransientObjectsExceeded for easy import from scripts,
# this is protected by a module security info declaration in the
# Sessions package.
from Transience import MaxTransientObjectsExceeded
def initialize(context):
context.registerClass(
Transience.TransientObjectContainer,
permission=Transience.ADD_CONTAINER_PERM,
constructors=(Transience.constructTransientObjectContainerForm,
Transience.constructTransientObjectContainer)
)
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Transient Object Container'
)">
<FORM ACTION="constructTransientObjectContainer" METHOD="POST">
<TABLE CELLSPACING="2">
<tr>
<div class="form-help">
<td colspan="2">
<p>
Transient Object Containers are used to store transient data.
Transient data will persist, but only for a user-specified period of time,
(the "data object timeout") after which it will be flushed.
</p>
<p>
It is recommended that Transient Object Containers be added to storages which
do not support undo operations; transient objects are write-intensive;
their use may cause many undoable transactions, potentially bloating
undoing ZODB databases.
</p>
<p>
Transient Object Containers support <b>Add and Delete Scripts</b> which
are methods which are invoked when transient objects are added or deleted
from the container. A add/delete script is invoked with the item being
operated upon and the transient object container as arguments. Specify
the Zope physical path to the method to be invoked to receive the notification
(e.g. '/folder/add_notifier').
</p>
</div>
</td>
</tr>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Id
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Title (optional)
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Data object timeout (in minutes)
</div>
<div class="form-help">
("0" means no expiration)
</div>
</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">
<div class="form-label">
Timeout resolution (in seconds)
</div>
<div class="form-help">
(accept the default if you're not sure)
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="period_secs:int" SIZE="10" value="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Maximum number of subobjects
</div>
<div class="form-help">
("0" means infinite)
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="limit:int" SIZE="10" value="1000">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Script to call upon object add (optional)
</div>
<div class="form-help">
(e.g. "/somefolder/addScript")
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="addNotification" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Script to call upon object delete (optional)
</div>
<div class="form-help">
(e.g. "/somefolder/delScript")
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="delNotification" SIZE="40">
</TD>
</TR>
<TR>
<TD>
</TD>
<TD> <BR><INPUT class="form-element" TYPE="SUBMIT" VALUE=" Add "> </TD>
</TR>
</TABLE>
</FORM>
<dtml-var manage_page_footer>
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
# This file is needed to make this a package.
import sys
import time as origtime
epoch = origtime.time()
resolution = 120.0
timeout = 30
if sys.platform[:3].lower() == "win":
resolution = 60.0
timeout = 60
def time():
""" False timer -- returns time R x faster than normal time """
return (origtime.time() - epoch) * resolution
def sleep(duration):
""" False sleep -- sleep for 1/R the time specifed """
origtime.sleep(duration / resolution)
import time as origtime
epoch = origtime.time()
def time():
""" False timer -- returns time 60 x faster than normal time """
return (origtime.time() - epoch) * 60
def sleep(duration):
""" False sleep -- sleep for 1/60 the time specifed """
origtime.sleep(duration / 60)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -20,6 +20,7 @@ Products.BTreeFolder2 = 3.0
Products.ExternalMethod = 3.0
Products.MailHost = 3.0
Products.PythonScripts = 3.0
Products.Sessions = 4.0
Products.SiteErrorLog = 4.0
Products.StandardCacheManagers = 3.0
Products.ZCatalog = 4.0a1
......
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