text: ##############################################################################
  #
  # 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.
  #
  ##############################################################################
  """ Customizable ZSQL methods that come from the filesystem.
  """
  
  import logging
  
  from AccessControl.SecurityInfo import ClassSecurityInfo
  from Acquisition import ImplicitAcquisitionWrapper
  from App.class_init import InitializeClass
  from App.config import getConfiguration
  from App.special_dtml import DTMLFile
  from Products.ZSQLMethods.SQL import SQL
  
  from Products.CMFCore.DirectoryView import registerFileExtension
  from Products.CMFCore.DirectoryView import registerMetaType
  from Products.CMFCore.FSObject import FSObject
  from Products.CMFCore.permissions import View
  from Products.CMFCore.permissions import ViewManagementScreens
  from Products.CMFCore.utils import _dtmldir
  
  logger = logging.getLogger('CMFCore.FSZSQLMethod')
  
  
  class FSZSQLMethod(SQL, FSObject):
  
      """FSZSQLMethods act like Z SQL Methods but are not directly
      modifiable from the management interface."""
  
      meta_type = 'Filesystem Z SQL Method'
  
      manage_options = (
          {'label': 'Customize', 'action': 'manage_customise'},
          {'label': 'Test', 'action': 'manage_testForm',
           'help': ('ZSQLMethods', 'Z-SQL-Method_Test.stx')})
  
      security = ClassSecurityInfo()
      security.declareObjectProtected(View)
  
      # Make mutators private
      security.declarePrivate('manage_main')
      security.declarePrivate('manage_edit')
      security.declarePrivate('manage_advanced')
      security.declarePrivate('manage_advancedForm')
      manage = None
  
      security.declareProtected(ViewManagementScreens, 'manage_customise')
      manage_customise = DTMLFile('custzsql', _dtmldir)
  
      def __init__(self, id, filepath, fullname=None, properties=None):
          FSObject.__init__(self, id, filepath, fullname, properties)
  
      def _createZODBClone(self):
          """Create a ZODB (editable) equivalent of this object."""
          # I guess it's bad to 'reach inside' ourselves like this,
          # but Z SQL Methods don't have accessor methdods ;-)
          s = SQL(self.id,
                  self.title,
                  self.connection_id,
                  self.arguments_src,
                  self.src)
          s.manage_advanced(self.max_rows_,
                            self.max_cache_,
                            self.cache_time_,
                            self.class_name_,
                            self.class_file_,
                            connection_hook=self.connection_hook,
                            direct=self.allow_simple_one_argument_traversal)
          return s
  
      def _readFile(self, reparse):
          """Read the data from the filesystem.
          """
          file = open(self._filepath, 'r') # not 'rb', as this is a text file!
          try:
              data = file.read()
          finally:
              file.close()
  
          # parse parameters
          parameters = {}
          start = data.find('<dtml-comment>')
          end = data.find('</dtml-comment>')
          if start == -1 or end == -1 or start > end:
              raise ValueError('Could not find parameter block')
          block = data[start + 14:end]
  
          for line in block.split('\n'):
              pair = line.split(':', 1)
              if len(pair) != 2:
                  continue
              parameters[pair[0].strip().lower()] = pair[1].strip()
  
          # check for required parameters
          try:
              connection_id = (parameters.get('connection id', '') or
                                  parameters['connection_id'])
          except KeyError, e:
              raise ValueError("The '%s' parameter is required "
                               "but was not supplied" % e)
  
          # Optional parameters
          title = parameters.get('title', '')
          arguments = parameters.get('arguments', '')
          max_rows = parameters.get('max_rows', 1000)
          max_cache = parameters.get('max_cache', 100)
          cache_time = parameters.get('cache_time', 0)
          class_name = parameters.get('class_name', '')
          class_file = parameters.get('class_file', '')
          connection_hook = parameters.get('connection_hook', None)
          direct = parameters.get('allow_simple_one_argument_traversal', None)
  
          self.manage_edit(title, connection_id, arguments, template=data)
  
          self.manage_advanced(max_rows,
                               max_cache,
                               cache_time,
                               class_name,
                               class_file,
                               connection_hook=connection_hook,
                               direct=direct)
  
          # do we need to do anything on reparse?
  
      if getConfiguration().debug_mode:
          # Provide an opportunity to update the properties.
          def __of__(self, parent):
              try:
                  self = ImplicitAcquisitionWrapper(self, parent)
                  self._updateFromFS()
                  return self
              except:
                  logger.exception("Error during __of__")
                  raise
  
  InitializeClass(FSZSQLMethod)
  
  registerFileExtension('zsql', FSZSQLMethod)
  registerMetaType('Z SQL Method', FSZSQLMethod)
  