[CMF-checkins] CVS: CMF/CMFCore - DirectoryView.py:1.32 FSDTMLMethod.py:1.13 FSFile.py:1.4 FSImage.py:1.13 FSObject.py:1.13 FSPageTemplate.py:1.17 FSPythonScript.py:1.20

Andy McKay andy@agmweb.ca
Fri, 8 Nov 2002 19:25:23 -0500


Update of /cvs-repository/CMF/CMFCore
In directory cvs.zope.org:/tmp/cvs-serv11724

Modified Files:
	DirectoryView.py FSDTMLMethod.py FSFile.py FSImage.py 
	FSObject.py FSPageTemplate.py FSPythonScript.py 
Log Message:
All these objects now have a Cacheable interface so you can cache them using a RAMCacheManager for instance. To do this you specify the cache id in the properties file:

eg: cache=SomeCache


=== CMF/CMFCore/DirectoryView.py 1.31 => 1.32 ===
--- CMF/CMFCore/DirectoryView.py:1.31	Tue Oct 22 16:58:18 2002
+++ CMF/CMFCore/DirectoryView.py	Fri Nov  8 19:25:23 2002
@@ -421,6 +421,8 @@
     all_meta_types = ()
     _isDirectoryView = 1
 
+#    _is_wrapperish = 1
+
     security = ClassSecurityInfo()
 
     def __init__(self, real, data, objects):
@@ -447,7 +449,7 @@
         if REQUEST is not None:
             REQUEST['RESPONSE'].redirect( '%s/manage_propertiesForm'
                                         % self.absolute_url() )
-    
+
     security.declareProtected(AccessContentsInformation, 'getCustomizableObject')
     def getCustomizableObject(self):
         ob = aq_parent(aq_inner(self))


=== CMF/CMFCore/FSDTMLMethod.py 1.12 => 1.13 ===
--- CMF/CMFCore/FSDTMLMethod.py:1.12	Fri Aug 16 09:45:05 2002
+++ CMF/CMFCore/FSDTMLMethod.py	Fri Nov  8 19:25:23 2002
@@ -28,12 +28,16 @@
 from CMFCorePermissions import FTPAccess
 from DirectoryView import registerFileExtension, registerMetaType, expandpath
 from FSObject import FSObject
+
 try:
     # Zope 2.4.x
     from AccessControl.DTML import RestrictedDTML
 except ImportError:
     class RestrictedDTML: pass
 
+from OFS.Cache import Cacheable
+
+_marker = []  # Create a new marker object.
 
 class FSDTMLMethod(RestrictedDTML, FSObject, Globals.HTML):
     """FSDTMLMethods act like DTML methods but are not directly
@@ -47,8 +51,11 @@
             {'label':'View', 'action':'',
              'help':('OFSP','DTML-DocumentOrMethod_View.stx')},
             )
+            +Cacheable.manage_options
         )
 
+    _cache_namespace_keys=()
+
     # Use declarative security
     security = ClassSecurityInfo()
     security.declareObjectProtected(View)
@@ -105,6 +112,12 @@
 
         self._updateFromFS()
 
+        if not self._cache_namespace_keys:
+            data = self.ZCacheable_get(default=_marker)
+            if data is not _marker:
+                # Return cached results.
+                return data
+
         kw['document_id']   =self.getId()
         kw['document_title']=self.title
 
@@ -117,10 +130,14 @@
                 r=apply(Globals.HTML.__call__, (self, client, REQUEST), kw)
                 if RESPONSE is None: result = r
                 else: result = decapitate(r, RESPONSE)
+                if not self._cache_namespace_keys:
+                    self.ZCacheable_set(result)
                 return result
 
             r=apply(Globals.HTML.__call__, (self, client, REQUEST), kw)
             if type(r) is not type('') or RESPONSE is None:
+                if not self._cache_namespace_keys:
+                    self.ZCacheable_set(result)
                 return r
 
         finally: security.removeContext(self)
@@ -133,7 +150,29 @@
                 c, e=guess_content_type(self.getId(), r)
             RESPONSE.setHeader('Content-Type', c)
         result = decapitate(r, RESPONSE)
+        if not self._cache_namespace_keys:
+            self.ZCacheable_set(result)
         return result
+
+    def getCacheNamespaceKeys(self):
+        '''
+        Returns the cacheNamespaceKeys.
+        '''
+        return self._cache_namespace_keys
+        
+    def setCacheNamespaceKeys(self, keys, REQUEST=None):
+        '''
+        Sets the list of names that should be looked up in the
+        namespace to provide a cache key.
+        '''
+        ks = []
+        for key in keys:
+            key = strip(str(key))
+            if key:
+                ks.append(key)
+        self._cache_namespace_keys = tuple(ks)
+        if REQUEST is not None:
+            return self.ZCacheable_manage(self, REQUEST)
 
     # Zope 2.3.x way:
     def validate(self, inst, parent, name, value, md=None):


=== CMF/CMFCore/FSFile.py 1.3 => 1.4 ===
--- CMF/CMFCore/FSFile.py:1.3	Mon Nov  4 14:56:35 2002
+++ CMF/CMFCore/FSFile.py	Fri Nov  8 19:25:23 2002
@@ -27,6 +27,8 @@
 from FSObject import FSObject
 from DirectoryView import registerFileExtension, registerMetaType, expandpath
 
+from OFS.Cache import Cacheable
+
 class FSFile(FSObject):
     """FSFiles act like images but are not directly
     modifiable from the management interface."""
@@ -36,7 +38,7 @@
 
     manage_options=(
         {'label':'Customize', 'action':'manage_main'},
-        )
+        ) + Cacheable.manage_options
 
     security = ClassSecurityInfo()
     security.declareObjectProtected(View)
@@ -77,6 +79,7 @@
         try: data = file.read()
         finally: file.close()
         if reparse or self.content_type == 'unknown/unknown':
+            self.ZCacheable_invalidate()
             self.content_type=self._get_content_type(file, data, self.id)
         return data
 
@@ -121,6 +124,7 @@
         RESPONSE.setHeader('Content-Type', self.content_type)
         RESPONSE.setHeader('Content-Length', len(data))
 
+        self.ZCacheable_set(None)
         return data
 
     security.declareProtected(View, 'getContentType')


=== CMF/CMFCore/FSImage.py 1.12 => 1.13 ===
--- CMF/CMFCore/FSImage.py:1.12	Thu Aug  1 15:05:11 2002
+++ CMF/CMFCore/FSImage.py	Fri Nov  8 19:25:23 2002
@@ -28,6 +28,8 @@
 from FSObject import FSObject
 from DirectoryView import registerFileExtension, registerMetaType, expandpath
 
+from OFS.Cache import Cacheable
+
 class FSImage(FSObject):
     """FSImages act like images but are not directly
     modifiable from the management interface."""
@@ -39,7 +41,7 @@
 
     manage_options=(
         {'label':'Customize', 'action':'manage_main'},
-        )
+        ) + Cacheable.manage_options
 
     security = ClassSecurityInfo()
     security.declareObjectProtected(View)
@@ -63,6 +65,7 @@
         finally:
             file.close()
         if reparse or self.content_type == 'unknown/unknown':
+            self.ZCacheable_invalidate()
             ct, width, height = getImageInfo( data )
             self.content_type = ct
             self.width = width
@@ -117,6 +120,7 @@
         RESPONSE.setHeader('Content-Type', self.content_type)
         RESPONSE.setHeader('Content-Length', len(data))
 
+        self.ZCacheable_set(None)
         return data
 
     security.declareProtected(View, 'getContentType')


=== CMF/CMFCore/FSObject.py 1.12 => 1.13 ===
--- CMF/CMFCore/FSObject.py:1.12	Thu Aug 15 16:03:09 2002
+++ CMF/CMFCore/FSObject.py	Fri Nov  8 19:25:23 2002
@@ -28,7 +28,9 @@
 from CMFCorePermissions import ViewManagementScreens
 from CMFCorePermissions import ManagePortal
 
-class FSObject(Acquisition.Implicit, Item):
+from OFS.Cache import Cacheable
+
+class FSObject(Acquisition.Implicit, Item, Cacheable):
     """FSObject is a base class for all filesystem based look-alikes.
     
     Subclasses of this class mimic ZODB based objects like Image and
@@ -53,6 +55,10 @@
             if fullname and properties.get('keep_extension', 0):
                 id = fullname
 
+            cache = properties.get('cache')
+            if cache:
+                self.ZCacheable_setManagerId(cache)
+
         self.id = id
         self.__name__ = id # __name__ is used in traceback reporting
         self._filepath = filepath
@@ -104,6 +110,8 @@
             try:    mtime=stat(fp)[8]
             except: mtime=0
             if not parsed or mtime != self._file_mod_time:
+                # if we have to read the file again, remove the cache
+                self.ZCacheable_invalidate()
                 self._readFile(1)
                 self._file_mod_time = mtime
                 self._parsed = 1


=== CMF/CMFCore/FSPageTemplate.py 1.16 => 1.17 ===
--- CMF/CMFCore/FSPageTemplate.py:1.16	Mon Nov  4 16:44:34 2002
+++ CMF/CMFCore/FSPageTemplate.py	Fri Nov  8 19:25:23 2002
@@ -37,6 +37,10 @@
 
 xml_detect_re = re.compile('^\s*<\?xml\s+')
 
+from OFS.Cache import Cacheable
+
+_marker = []  # Create a new marker object.
+
 class FSPageTemplate(FSObject, Script, PageTemplate):
     "Wrapper for Page Template"
      
@@ -47,7 +51,8 @@
             {'label':'Customize', 'action':'manage_main'},
             {'label':'Test', 'action':'ZScriptHTML_tryForm'},
             )
-        )
+            +Cacheable.manage_options
+        ) 
 
     security = ClassSecurityInfo()
     security.declareObjectProtected(View)
@@ -69,8 +74,8 @@
         obj.write(self.read())
         return obj
 
-    def ZCacheable_isCachingEnabled(self):
-        return 0
+#    def ZCacheable_isCachingEnabled(self):
+#        return 0
 
     def _readFile(self, reparse):
         fp = expandpath(self._filepath)
@@ -162,8 +167,49 @@
             response = None
         # Read file first to get a correct content_type default value.
         self._updateFromFS()
-        # call "inherited"
-        result = self._ZPT_exec( bound_names, args, kw )
+        
+        if not kw.has_key('args'):
+            kw['args'] = args
+        bound_names['options'] = kw
+
+        try:
+            response = self.REQUEST.RESPONSE
+            if not response.headers.has_key('content-type'):
+                response.setHeader('content-type', self.content_type)
+        except AttributeError:
+            pass
+            
+        security=getSecurityManager()
+        bound_names['user'] = security.getUser()
+
+        # Retrieve the value from the cache.
+        keyset = None
+        if self.ZCacheable_isCachingEnabled():
+            # Prepare a cache key.
+            keyset = {
+                      # Why oh why?
+                      # All this code is cut and paste
+                      # here to make sure that we 
+                      # dont call _getContext and hence can't cache
+                      # Annoying huh?
+                      'here': self.aq_parent.getPhysicalPath(),
+                      'bound_names': bound_names}
+            result = self.ZCacheable_get(keywords=keyset)
+            if result is not None:
+                # Got a cached value.
+                return result
+
+        # Execute the template in a new security context.
+        security.addContext(self)
+        try:
+            result = self.pt_render(extra_context=bound_names)
+            if keyset is not None:
+                # Store the result in the cache.
+                self.ZCacheable_set(result, keywords=keyset)
+            return result
+        finally:
+            security.removeContext(self)
+        
         return result
  
     # Copy over more methods


=== CMF/CMFCore/FSPythonScript.py 1.19 => 1.20 ===
--- CMF/CMFCore/FSPythonScript.py:1.19	Fri Nov  8 12:10:01 2002
+++ CMF/CMFCore/FSPythonScript.py	Fri Nov  8 19:25:23 2002
@@ -30,6 +30,9 @@
 from DirectoryView import registerFileExtension, registerMetaType, expandpath
 from FSObject import FSObject
 
+from OFS.Cache import Cacheable
+
+_marker = []
 
 class bad_func_code:
     co_varnames = ()
@@ -51,6 +54,7 @@
              'action':'ZScriptHTML_tryForm',
              'help': ('PythonScripts', 'PythonScript_test.stx')},
             )
+            + Cacheable.manage_options
         )
 
     # Use declarative security
@@ -103,6 +107,26 @@
 
         Calling a Python Script is an actual function invocation.
         """
+        # do caching
+        keyset = None
+        if self.ZCacheable_isCachingEnabled():
+            # Prepare a cache key.
+            keyset = kw.copy()
+            asgns = self.getBindingAssignments()
+            name_context = asgns.getAssignedName('name_context', None)
+            if name_context:
+                keyset[name_context] = self.aq_parent.getPhysicalPath()
+            name_subpath = asgns.getAssignedName('name_subpath', None)
+            if name_subpath:
+                keyset[name_subpath] = self._getTraverseSubpath()
+            # Note: perhaps we should cache based on name_ns also.
+            keyset['*'] = args
+            result = self.ZCacheable_get(keywords=keyset, default=_marker)
+            if result is not _marker:
+                # Got a cached value.
+                return result
+
+        
         # Prepare the function.
         f = self._v_f
         if f is None:
@@ -131,6 +155,9 @@
         security.addContext(self)
         try:
             result = apply(f, args, kw)
+            if keyset is not None:
+                # Store the result in the cache.
+                self.ZCacheable_set(result, keywords=keyset)           
             return result
         finally:
             security.removeContext(self)