[Zope-Checkins] CVS: Zope3/lib/python/Zope/StartUp - RequestFactory.py:1.1.2.1 RequestFactoryRegistry.py:1.1.2.1 ServerType.py:1.1.2.1 ServerTypeRegistry.py:1.1.2.1 SiteDefinition.py:1.1.2.1 startup-registry.zcml:1.1.2.1 __init__.py:1.1.2.2 metaConfigure.py:1.1.2.2 startup-meta.zcml:1.1.2.2

Stephan Richter srichter@cbu.edu
Sat, 30 Mar 2002 02:02:16 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/StartUp
In directory cvs.zope.org:/tmp/cvs-serv25616/lib/python/Zope/StartUp

Modified Files:
      Tag: Zope-3x-branch
	__init__.py metaConfigure.py startup-meta.zcml 
Added Files:
      Tag: Zope-3x-branch
	RequestFactory.py RequestFactoryRegistry.py ServerType.py 
	ServerTypeRegistry.py SiteDefinition.py startup-registry.zcml 
Log Message:
I played with the startup directives some more and separated the programmer
directives from the site admins. One can now easily create new sites
without knowing anything about Zope. The only thing s/he has to know is the
name of the server (i.e. Browser) s/he wants to start for a particular
site.

There is also registries now for RequestFactories and and ServerTypes, so 
that third party programmers can easily add their own request factories and
server types to the system by calling a couple of directives. That makes it
also really plugable, since one could simply exchange the Logger of a server
without much hassle.

Also, each storage type has its own directive now, since arguments for the
constructors of the storages greatly vary. 

Note: The directives now are probably not flexible enough for future use,
      but we can add complexity as we need it later.  



=== Added File Zope3/lib/python/Zope/StartUp/RequestFactory.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
# 
##############################################################################
"""

$Id: RequestFactory.py,v 1.1.2.1 2002/03/30 07:02:14 srichter Exp $
"""

from Interface import Interface
import copy


class IRequestFactory(Interface):
    """This is a pure read-only interface, since the values are set through
       a ZCML directive and we shouldn't be able to change them.
    """

    def realize(db):
        """Realize the factory by initalizing the publication.

           The method returns the realized object.
        """
        

    def __call__(input_stream, output_steam, env):
        """Call the Request Factory"""





class RequestFactory:
    """This class will generically create RequestFactories. This way I do
       not have to create a method for each Server Type there is.
    """

    __implements__ =  IRequestFactory

    def __init__(self, publication, request):
        """Initialize Request Factory"""
        self._pubFactory = publication
        self._publication = None
        self._request = request


    ############################################################
    # Implementation methods for interface
    # Zope.StartUp.RequestFactory.IRequestFactory

    def realize(self, db):
        'See Zope.StartUp.RequestFactory.IRequestFactory'
        realized = copy.copy(self)
        realized._publication = realized._pubFactory(db)
        return realized
    

    def __call__(self, input_stream, output_steam, env):
        'See Zope.StartUp.RequestFactory.IRequestFactory'
        request = self._request(input_stream, output_steam, env)
        request.setPublication(self._publication)
        return request

    #
    ############################################################


=== Added File Zope3/lib/python/Zope/StartUp/RequestFactoryRegistry.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
# 
##############################################################################
"""

$Id: RequestFactoryRegistry.py,v 1.1.2.1 2002/03/30 07:02:14 srichter Exp $
"""


from Zope.App.Formulator.SimpleRegistry import SimpleRegistry
from Zope.App.Formulator.ISimpleRegistry import ISimpleRegistry
from RequestFactory import IRequestFactory 

class IRequestFactoryRegistry(ISimpleRegistry):
    """
    The RequestFactory Registry manages a list of all the fields
    available in Zope. A registry is useful at this point, since
    fields can be initialized and registered by many places.

    Note that it does not matter whether we have classes or instances as
    fields. If the fields are instances, they must implement
    IInstanceFactory.
    """
    pass


class RequestFactoryRegistry(SimpleRegistry):
    """ """

    __implements__ =  (IRequestFactoryRegistry,)



RequestFactoryRegistry = RequestFactoryRegistry(IRequestFactory)
registerRequestFactory = RequestFactoryRegistry.register
getRequestFactory = RequestFactoryRegistry.get


=== Added File Zope3/lib/python/Zope/StartUp/ServerType.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
# 
##############################################################################
"""

$Id: ServerType.py,v 1.1.2.1 2002/03/30 07:02:14 srichter Exp $
"""

from Interface import Interface
from RequestFactoryRegistry import getRequestFactory


class IServerType(Interface):
    """This is a pure read-only interface, since the values are set through
       a ZCML directive and we shouldn't be able to change them.
    """

    def create(task_dispatcher, db, port=None, verbose=None):
        """Create the server knowing the port, task dispatcher and the ZODB.
        """


class ServerType:

    __implements__ =  IServerType


    def __init__(self, name, factory, requestFactory, logFactory,
                 defaultPort, defaultVerbose):
        """ """
        self._name = name
        self._factory = factory
        self._requestFactory = requestFactory
        self._logFactory = logFactory
        self._defaultPort = defaultPort
        self._defaultVerbose = defaultVerbose


    ############################################################
    # Implementation methods for interface
    # Zope.StartUp.ServerType.IServerType

    def create(self, task_dispatcher, db, port=None, verbose=None):
        'See Zope.StartUp.ServerType.IServerType'


        request_factory = getRequestFactory(self._requestFactory)
        request_factory = request_factory.realize(db)

        if port is None:
            port = self._defaultPort

        if verbose is None:
            verbose = self._defaultVerbose

        apply(self._factory,
              (request_factory, self._name, '', port),
              {'task_dispatcher': task_dispatcher,
               'verbose': verbose,
               'hit_log': self._logFactory()})

    #
    ############################################################

        


=== Added File Zope3/lib/python/Zope/StartUp/ServerTypeRegistry.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
# 
##############################################################################
"""

$Id: ServerTypeRegistry.py,v 1.1.2.1 2002/03/30 07:02:14 srichter Exp $
"""


from Zope.App.Formulator.SimpleRegistry import SimpleRegistry
from Zope.App.Formulator.ISimpleRegistry import ISimpleRegistry
from ServerType import IServerType 

class IServerTypeRegistry(ISimpleRegistry):
    """
    The ServerType Registry manages a list of all the fields
    available in Zope. A registry is useful at this point, since
    fields can be initialized and registered by many places.

    Note that it does not matter whether we have classes or instances as
    fields. If the fields are instances, they must implement
    IInstanceFactory.
    """
    pass


class ServerTypeRegistry(SimpleRegistry):
    """ """

    __implements__ =  (IServerTypeRegistry,)



ServerTypeRegistry = ServerTypeRegistry(IServerType)
registerServerType = ServerTypeRegistry.register
getServerType = ServerTypeRegistry.get


=== Added File Zope3/lib/python/Zope/StartUp/SiteDefinition.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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 module handles the :startup directives. 

$Id: SiteDefinition.py,v 1.1.2.1 2002/03/30 07:02:14 srichter Exp $
"""

import sys

# Import Configuration-related classes
from Zope.Configuration.Action import Action
from Zope.Configuration.ConfigurationDirectiveInterfaces \
     import INonEmptyDirective

from ServerTypeRegistry import getServerType

# Import Undo-related classes 
from Zope.ComponentArchitecture import provideUtility
from Zope.App.Undo.ZODBUndoManager import ZODBUndoManager
from Zope.App.Undo.IUndoManager import IUndoManager


from Zope.App.OFS.Folder.RootFolder import RootFolder
import asyncore, zLOG
from Zope.Server import ZLogIntegration
from Zope.Server.TaskThreads import ThreadedTaskDispatcher
from Zope.App.ZopePublication.ZopePublication import ZopePublication

import asyncore, zLOG

from ZODB import DB


DEFAULT_STORAGE_FILE = 'Data.fs'
DEFAULT_LOG_FILE = 'STDERR'
DEFAULT_LOG_CLASS = 'Zope.Server.HTTPServer.CommonHitLogger'


class SiteDefinition:

    __class_implements__ = INonEmptyDirective    

    # Some special file names for log files
    _special_log_files = {'STDERR': sys.stderr,
                          'STDOUT': sys.stdout}

    
    def __init__(self, _context, name="default", threads=4):
        """Initilize is called, when the defineSite directive is invoked.
        """
        self._name = name
        self._threads = int(threads)

        self._zodb = None
        self.useLog(_context)
        self._servers = {}

        self._started = 0


    def useFileStorage(self, _context, file=DEFAULT_STORAGE_FILE):
        """Lets you specify the ZODB to use."""
        from ZODB.FileStorage import FileStorage
        self._zodb = DB(FileStorage(file))
        return []


    def useMappingStorage(self, _context):
        """Lets you specify the ZODB to use."""
        from ZODB.MappingStorage import MappingStorage
        self._zodb = DB(MappingStorage(file))
        return []


    def useLog(self, _context, file=DEFAULT_LOG_FILE):
        """Lets you specify the log file to use"""

        if file in self._special_log_files.keys():
            file = self._special_log_files[file]
        else:
            file = open(file, 'w')

        zLOG._set_log_dest(file)
        return []


    def addServer(self, _context, type, port=None, verbose=None):
        """Add a new server for this site."""

        if port is not None:
            port = int(port)

        if verbose is not None:
            if verbose.lower() == 'true': verbose = 1
            else: verbose = 0

        if type is not None:
            self._servers[type] = {'port': port,
                                   'verbose': verbose}
        else:
            sys.stderr.out('Warning: Server of Type %s does not exist. ' +
                           'Directive neglected.') 
        return []


    def start(self):
        """Now start all the servers"""

        sys.stderr.write('\nStarting Site: %s\n\n' %self._name)

        sys.setcheckinterval(120)
        
        # setup undo fnctionality
        provideUtility(IUndoManager, ZODBUndoManager(self._zodb))
        
        # Setup the task dispatcher
        td = ThreadedTaskDispatcher()
        td.setThreadCount(self._threads)
        
        # setup the storage, if not already done
        if self._zodb is None:
            self.useStorage(_context)
        
        # check whether a root was already specified for this ZODB; if
        # not create one.
        self._initDB()
        
        # Start the servers
        for type, server_info in self._servers.items():

            server = getServerType(type)

            server.create(td, self._zodb, server_info['port'],
                          server_info['verbose'])
        

    def _initDB(self):
        """Initialize the ZODB"""

        connection = self._zodb.open()
        root = connection.root()
        app = root.get(ZopePublication.root_name, None)

        if app is None:

            from Zope.App.OFS.Folder.RootFolder import RootFolder
            from Transaction import get_transaction
        
            app = RootFolder()
            root[ZopePublication.root_name] = app

            get_transaction().commit()

        connection.close()


    def __call__(self):
        "Handle empty/simple declaration."
        return [ Action(discriminator = 'Start Servers',
                        callable = self.start,
                        args = (),
                        ) ]    


=== Added File Zope3/lib/python/Zope/StartUp/startup-registry.zcml ===
<zopeConfigure
   xmlns="http://namespaces.zope.org/zope"
   xmlns:startup="http://namespaces.zope.org/startup">


  <startup:registerRequestFactory name="BrowserRequestFactory"
    publication = 
    "Zope.App.ZopePublication.Browser.Publication.BrowserPublication"
    request = "Zope.Publisher.Browser.BrowserRequest." 
  />


  <startup:registerRequestFactory name="XMLRPCRequestFactory" 
    publication = 
    "Zope.App.ZopePublication.XMLRPC.Publication.XMLRPCPublication"
    request = "Zope.Publisher.XMLRPC.XMLRPCRequest." 
  />


  <startup:registerServerType 
    name = "Browser"
    factory = "Zope.Server.PublisherServers.PublisherHTTPServer"
    requestFactory="BrowserRequestFactory"
    logFactory = "Zope.Server.HTTPServer.CommonHitLogger"
    defaultPort="8080"
    defaultVerbose="true" />


  <startup:registerServerType 
    name = "XML-RPC"
    factory = "Zope.Server.PublisherServers.PublisherHTTPServer"
    requestFactory="XMLRPCRequestFactory"
    logFactory = "Zope.Server.HTTPServer.CommonHitLogger"
    defaultPort="8081"
    defaultVerbose="true" />


</zopeConfigure>


=== Zope3/lib/python/Zope/StartUp/__init__.py 1.1.2.1 => 1.1.2.2 ===


=== Zope3/lib/python/Zope/StartUp/metaConfigure.py 1.1.2.1 => 1.1.2.2 ===
 """
 
-import sys
-
-# Import Configuration-related classes
+from SiteDefinition import SiteDefinition
 from Zope.Configuration.Action import Action
-from Zope.Configuration.ConfigurationDirectiveInterfaces \
-     import INonEmptyDirective
-
-# Import Undo-related classes 
-from Zope.ComponentArchitecture import provideUtility
-from Zope.App.Undo.ZODBUndoManager import ZODBUndoManager
-from Zope.App.Undo.IUndoManager import IUndoManager
-
-# Import Server-related
-from Zope.Publisher.Browser.BrowserRequest import BrowserRequest
-from Zope.App.ZopePublication.Browser.Publication import BrowserPublication
-
-from Zope.Publisher.XMLRPC.XMLRPCRequest import XMLRPCRequest
-from Zope.App.ZopePublication.XMLRPC.Publication import XMLRPCPublication
-
-
-from Zope.App.Security.SimpleSecurityPolicies \
-     import PermissiveSecurityPolicy
-from Zope.App.Security.SecurityManager import setSecurityPolicy
-from Zope.App.OFS.Folder.RootFolder import RootFolder
-import asyncore, zLOG
-from Zope.Server import ZLogIntegration
-from Zope.Server.PublisherServers import PublisherHTTPServer
-from Zope.Server.TaskThreads import ThreadedTaskDispatcher
-from Zope.Server.HTTPServer import CommonHitLogger
-from Zope.App.ZopePublication.ZopePublication import ZopePublication
-
-import asyncore, zLOG
-
-from ZODB.FileStorage import FileStorage
-from ZODB import DB
-
-
-DEFAULT_STORAGE = 'ZODB.FileStorage.'
-DEFAULT_STORAGE_FILE = 'Data.fs'
-DEFAULT_LOG_FILE = 'STDERR'
-DEFAULT_LOG_CLASS = 'Zope.Server.HTTPServer.CommonHitLogger'
-DEFAULT_SERVER_VERBOSE = 'true'
-
-
-class SiteDefinition:
-
-    __class_implements__ = INonEmptyDirective    
-
-    # I wish we could specify this through the ZCML script, but I think
-    # that would be too low level. 
-    _server_types = {'Browser': (PublisherHTTPServer, BrowserPublication,
-                                 BrowserRequest),
-                     'XML-RPC': (PublisherHTTPServer, XMLRPCPublication,
-                                 XMLRPCRequest),
-                     'SOAP': None,
-                     'FTP': None}
-
-    # Some special file names for log files
-    _special_log_files = {'STDERR': sys.stderr,
-                          'STDOUT': sys.stdout}
-
-    
-    def __init__(self, _context, name="default", threads=4):
-        """Initilize is called, when the defineSite directive is invoked.
-        """
-        self._name = name
-        self._threads = int(threads)
-
-        self._zodb = None
-        self.useLog(_context)
-        self._servers = {}
-
-        self._started = 0
-
-
-    def useStorage(self, _context, factory=DEFAULT_STORAGE,
-                   file=DEFAULT_STORAGE_FILE):
-        """Lets you specify the ZODB to use."""
-        storage = _context.resolve(factory)
-        self._zodb = DB(storage(file))
-        return []
-    
-
-    def useLog(self, _context, file=DEFAULT_LOG_FILE):
-        """Lets you specify the log file to use"""
-
-        if file in self._special_log_files.keys():
-            file = self._special_log_files[file]
-        else:
-            file = open(file, 'w')
-
-        zLOG._set_log_dest(file)
-        return []
-
-
-    def addServer(self, _context, type='Browser', port='8081',
-                  logClass=DEFAULT_LOG_CLASS, verbose='true'):
-        """Add a new server for this site."""
-
-        if verbose.lower() == 'true':
-            verbose = 1
-        else:
-            verbose = 0
-
-        logClass = _context.resolve(logClass)
-
-        server_info = self._server_types.get(type, None)
-
-        if type is not None:
-            self._servers[type] = {'server': server_info[0],
-                                    'publication': server_info[1],
-                                    'request': server_info[2],
-                                    'port': int(port),
-                                    'logClass': logClass,
-                                    'verbose': verbose}
-
-            return [ Action(discriminator = 'Start Servers',
-                           callable = self.start,
-                           args = (),
-                           ) ]
-        else:
-            sys.stderr.out('Warning: Server of Type %s does not exist. ' +
-                           'Directive neglected.') 
-            return []
-
+from RequestFactory import RequestFactory
+import RequestFactoryRegistry 
+from ServerType import ServerType
+import ServerTypeRegistry 
 
-    def start(self):
-        """Now start all the servers"""
-
-        sys.stderr.write('\nStarting Site: %s\n\n' %self._name)
-
-        if not self._started:
-            sys.setcheckinterval(120)
-
-            # setup undo fnctionality
-            provideUtility(IUndoManager, ZODBUndoManager(self._zodb))
-
-            # Setup the task dispatcher
-            td = ThreadedTaskDispatcher()
-            td.setThreadCount(self._threads)
-
-            # setup the storage, if not already done
-            if self._zodb is None:
-                self.useStorage(_context)
-
-            # check whether a root was already specified for this ZODB; if
-            # not create one.
-            self._initDB()
-
-            # Start the servers
-            for type, server_info in self._servers.items():
-                request_factory = RequestFactory(
-                    server_info['publication'](self._zodb),
-                    server_info['request'])
-                apply(server_info['server'],
-                      (request_factory, type, '', server_info['port']),
-                      {'task_dispatcher': td,
-                       'verbose': server_info['verbose'],
-                       'hit_log': server_info['logClass']()})
-
-            self._started = 1
-        
-
-    def _initDB(self):
-        """Initialize the ZODB"""
-
-        connection = self._zodb.open()
-        root = connection.root()
-        app = root.get(ZopePublication.root_name, None)
-
-        if app is None:
-
-            from Zope.App.OFS.Folder.RootFolder import RootFolder
-            from Transaction import get_transaction
-        
-            app = RootFolder()
-            root[ZopePublication.root_name] = app
+defineSite = SiteDefinition
 
-            get_transaction().commit()
 
-        connection.close()
+def registerRequestFactory(_context, name, publication, request):
+    """ """
+    publication = _context.resolve(publication)
+    request = _context.resolve(request)
+    request_factory = RequestFactory(publication, request)
+
+    return [
+        Action(
+            discriminator = name,
+            callable = RequestFactoryRegistry.registerRequestFactory,
+            args = (name, request_factory,),
+            )
+        ]
+
+
+def registerServerType(_context, name, factory, requestFactory, logFactory,
+                       defaultPort, defaultVerbose):
+    """ """
+    factory = _context.resolve(factory)
+    logFactory = _context.resolve(logFactory)
+
+    if defaultVerbose.lower() == 'true':
+        defaultVerbose = 1
+    else:
+        defaultVerbose = 0
 
+    defaultPort = int(defaultPort)
 
-    def __call__(self):
-        "Handle empty/simple declaration."
-        return []
+    server_type = ServerType(name, factory, requestFactory, logFactory,
+                             defaultPort, defaultVerbose)
     
 
-defineSite = SiteDefinition
-
+    return [
+        Action(
+            discriminator = name,
+            callable = ServerTypeRegistry.registerServerType,
+            args = (name, server_type),
+            )
+        ]
 
-class RequestFactory:
-    """This class will generically create RequestFactories. This way I do
-       not have to create a method for each Server Type there is.
-    """
-
-    def __init__(self, publication, request):
-        """Initialize Request Factory"""
-        self._publication = publication
-        self._request = request
-
-
-    def __call__(self, input_stream, output_steam, env):
-        """Call the Request Factory"""
-        request = self._request(input_stream, output_steam, env)
-        request.setPublication(self._publication)
-        return request


=== Zope3/lib/python/Zope/StartUp/startup-meta.zcml 1.1.2.1 => 1.1.2.2 ===
                handler="Zope.StartUp.metaConfigure.defineSite">
 
-      <subdirective name="useStorage"
-                    attributes="factory, file" />
+      <subdirective name="useFileStorage"
+                    attributes="file" />
+
+      <subdirective name="useMappingStorage" />
 
       <subdirective name="useLog" attributes="file" />
 
@@ -15,6 +17,14 @@
                     attributes="type, port, verbose, logClass" />
 
     </directive>
+
+    <directive name="registerRequestFactory"
+               attributes="name, publication, request"
+               handler="Zope.StartUp.metaConfigure.registerRequestFactory" />
+
+    <directive name="registerServerType"
+               attributes="name, publication, request"
+               handler="Zope.StartUp.metaConfigure.registerServerType" />
 
   </directives>