[Zope3-checkins] CVS: Zope3/src/zope/app/process - __init__.py:1.1.2.1 bootstrap.py:1.1.2.1 component.xml:1.1.2.1 configure.zcml:1.1.2.1 datatypes.py:1.1.2.1 event.py:1.1.2.1 loghandlers.py:1.1.2.1 main.py:1.1.2.1 meta.zcml:1.1.2.1 metaconfigure.py:1.1.2.1 requestfactory.py:1.1.2.1 requestfactoryregistry.py:1.1.2.1 schema.xml:1.1.2.1 server.py:1.1.2.1 servertype.py:1.1.2.1 servertyperegistry.py:1.1.2.1 simpleregistry.py:1.1.2.1

Fred L. Drake, Jr. fred@zope.com
Mon, 23 Jun 2003 18:08:00 -0400


Update of /cvs-repository/Zope3/src/zope/app/process
In directory cvs.zope.org:/tmp/cvs-serv24536/src/zope/app/process

Added Files:
      Tag: fdrake-zconfig-in-zope-3-branch
	__init__.py bootstrap.py component.xml configure.zcml 
	datatypes.py event.py loghandlers.py main.py meta.zcml 
	metaconfigure.py requestfactory.py requestfactoryregistry.py 
	schema.xml server.py servertype.py servertyperegistry.py 
	simpleregistry.py 
Log Message:
Support ZConfig in Zope 3.

=== Added File Zope3/src/zope/app/process/__init__.py ===
# Make this a package.


=== Added File Zope3/src/zope/app/process/bootstrap.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""Bootstrap code.

This module contains code to bootstrap a Zope3 instance.  For example
it makes sure a root folder exists and creates and configures some
essential services.

$Id: bootstrap.py,v 1.1.2.1 2003/06/23 22:07:58 fdrake Exp $
"""
from transaction import get_transaction

from zope.app.traversing import traverse, traverseName
from zope.app.publication.zopepublication import ZopePublication
from zope.app.content.folder import RootFolder
from zope.app.services.servicenames import HubIds
from zope.app.services.servicenames import EventPublication, EventSubscription
from zope.app.services.servicenames import ErrorLogging
from zope.app.services.service import ServiceManager
from zope.app.services.service import ServiceRegistration
from zope.app.services.hub import ObjectHub
from zope.app.services.event import EventService
from zope.app.services.error import ErrorReportingService
from zope.app.services.principalannotation import PrincipalAnnotationService
from zope.proxy import removeAllProxies
from zope.app.event import publish
from zope.app.event.objectevent import ObjectCreatedEvent
from zope.app.event import function

def bootstrapInstance(event):
    """Bootstrap a Zope3 instance given a database object.

    This first checks if the root folder exists.  If it exists, nothing
    is changed.  If no root folder exists, one is added, and several
    essential services are added and configured.
    """
    db = event.database
    connection = db.open()
    root = connection.root()
    root_folder = root.get(ZopePublication.root_name, None)

    if root_folder is None:
        # Bootstrap code

        root_folder = RootFolder()
        addEssentialServices(root_folder)
        root[ZopePublication.root_name] = root_folder

        publish(root_folder, ObjectCreatedEvent(root_folder))
        get_transaction().commit()

    connection.close()


bootstrapInstance = function.Subscriber(bootstrapInstance)


def addEssentialServices(root_folder):
    """Add essential services.

    XXX This ought to be configurable.  For now, hardcode some
    services we know we all need.
    """
    service_manager = ServiceManager()
    root_folder.setServiceManager(service_manager)

    # The EventService class implements two services
    name = addConfigureService(root_folder, EventPublication, EventService)
    configureService(root_folder, EventSubscription, name)

    # Add the HubIds service, which subscribes itself to the event service
    name = addService(root_folder, HubIds, ObjectHub)
    configureService(root_folder, HubIds, name)

    # Sundry other services
    addConfigureService(root_folder, ErrorLogging,
                        ErrorReportingService, copy_to_zlog=True)
    addConfigureService(root_folder, 'PrincipalAnnotation',
                        PrincipalAnnotationService)


def addConfigureService(root_folder, service_type, service_factory, **kw):
    """Add and configure a service to the root folder."""
    name = addService(root_folder, service_type, service_factory, **kw)
    configureService(root_folder, service_type, name)
    return name

def addService(root_folder, service_type, service_factory, **kw):
    """Add a service to the root folder.

    The service is added to the default package and activated.
    This assumes the root folder already has a service manager,
    and that we add at most one service of each type.

    Returns the name of the service implementation in the default package.
    """
    # The code here is complicated by the fact that the registry
    # calls at the end require a fully context-wrapped
    # registration; hence all the traverse() and traverseName() calls.
    package_name = '/++etc++site/default'
    package = traverse(root_folder, package_name)
    name = service_type + '-1'
    service = service_factory()
    service = removeAllProxies(service)
    package.setObject(name, service)

    # Set additional attributes on the service
    for k, v in kw.iteritems():
        setattr(service, k, v)
    return name

def configureService(root_folder, service_type, name, initial_status='Active'):
    """Configure a service in the root folder."""
    package_name = '/++etc++site/default'
    package = traverse(root_folder, package_name)
    registration_manager = package.getRegistrationManager()
    registration =  ServiceRegistration(service_type,
                                        name,
                                        registration_manager)
    key = registration_manager.setObject("", registration)
    registration = traverseName(registration_manager, key)
    registration.status = initial_status


=== Added File Zope3/src/zope/app/process/component.xml ===
<component prefix="zope.app.process.datatypes">

  <abstracttype name="logging.loghandler"/>

  <sectiontype name="logging.base-log-handler">
    <description>
      Base type for most log handlers.  This is cannot be used as a
      loghandler directly since it doesn't implement the loghandler
      abstract section type.
    </description>
    <key name="dateformat" default="%Y-%m-%dT%H:%M:%S"/>
    <key name="level" default="notset" datatype=".logging_level"/>
  </sectiontype>

  <sectiontype name="logfile" datatype=".FileHandlerFactory"
               implements="logging.loghandler"
               extends="logging.base-log-handler">
    <key name="path" required="yes"/>
    <key name="format" default="------\n%(asctime)s %(message)s"
         datatype=".log_format"/>
  </sectiontype>

  <sectiontype name="syslog" datatype=".SyslogHandlerFactory"
               implements="logging.loghandler"
               extends="logging.base-log-handler">
    <key name="facility" default="user" datatype=".syslog_facility"/>
    <key name="address" datatype="socket-address" default="localhost:514"/>
    <key name="format" default="%(message)s"
         datatype=".log_format"/>
  </sectiontype>

  <sectiontype name="win32-eventlog" datatype=".Win32EventLogFactory"
               implements="logging.loghandler"
               extends="logging.base-log-handler">
    <key name="appname" default="Zope"/>
    <key name="format" default="%(message)s"
         datatype=".log_format"/>
  </sectiontype>

  <sectiontype name="http-logger" datatype=".HTTPHandlerFactory"
               implements="logging.loghandler"
               extends="logging.base-log-handler">
    <key name="url" default="http://localhost/" datatype=".http_handler_url"/>
    <key name="method" default="GET" datatype=".get_or_post"/>
    <key name="format" default="%(asctime)s %(message)s"
         datatype=".log_format"/>
  </sectiontype>

  <sectiontype name="email-notifier" datatype=".SMTPHandlerFactory"
               implements="logging.loghandler"
               extends="logging.base-log-handler">
    <key name="from" required="yes" attribute="fromaddr"/>
    <multikey name="to" required="yes" attribute="toaddrs"/>
    <key name="subject" default="Message from Zope"/>
    <key name="smtp-server" default="localhost" datatype="inet-address"/>
    <key name="format" default="%(asctime)s %(message)s"
         datatype=".log_format"/>
  </sectiontype>


  <sectiontype name="eventlog" datatype=".EventLogFactory">
     <key name="level" datatype=".logging_level" default="info"/>
     <multisection type="logging.loghandler" attribute="handlers" name="*"/>
  </sectiontype>

</component>


=== Added File Zope3/src/zope/app/process/configure.zcml ===
<zopeConfigure
   xmlns="http://namespaces.zope.org/zope"
   xmlns:startup="http://namespaces.zope.org/startup"
   xmlns:event="http://namespaces.zope.org/event">


  <startup:registerRequestFactory 
    name="HTTPRequestFactory"
    factory="zope.app.publication.httpfactory"
  />


  <startup:registerRequestFactory name="BrowserRequestFactory"
    publication = 
    "zope.app.publication.browser.BrowserPublication"
    request = "zope.publisher.browser.BrowserRequest" 
  />


  <startup:registerRequestFactory name="XMLRPCRequestFactory" 
    publication = 
    "zope.app.publication.xmlrpc.XMLRPCPublication"
    request = "zope.publisher.xmlrpc.XMLRPCRequest" 
  />


  <startup:registerRequestFactory name="FTPRequestFactory"
    publication = "zope.app.publication.ftp.FTPPublication"
    request = "zope.publisher.ftp.FTPRequest" 
  />


  <startup:registerServerType 
    name = "HTTP"
    factory = "zope.server.http.publisherhttpserver.PublisherHTTPServer"
    requestFactory="HTTPRequestFactory"
    logFactory = "zope.server.http.commonhitlogger.CommonHitLogger"
    defaultPort="8080"
    defaultVerbose="true" />

  <startup:registerServerType 
    name = "Browser"
    factory = "zope.server.http.publisherhttpserver.PublisherHTTPServer"
    requestFactory="BrowserRequestFactory"
    logFactory = "zope.server.http.commonhitlogger.CommonHitLogger"
    defaultPort="8080"
    defaultVerbose="true" />


  <startup:registerServerType 
    name = "XML-RPC"
    factory = "zope.server.http.publisherhttpserver.PublisherHTTPServer"
    requestFactory="XMLRPCRequestFactory"
    logFactory = "zope.server.http.commonhitlogger.CommonHitLogger"
    defaultPort="8081"
    defaultVerbose="true" />


  <startup:registerServerType 
    name = "FTP"
    factory = "zope.server.ftp.publisher.PublisherFTPServer"
    requestFactory="FTPRequestFactory"
    logFactory = "zope.server.ftp.logger.CommonFTPActivityLogger"
    defaultPort="8021"
    defaultVerbose="true" />


  <event:subscribe
    subscriber=".bootstrap.bootstrapInstance"
    event_types="zope.app.interfaces.event.IDatabaseOpenedEvent"
    />

</zopeConfigure>


=== Added File Zope3/src/zope/app/process/datatypes.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################

"""ZConfig datatypes for logging support."""

import sys

# log-related datatypes

_logging_levels = {
    "critical": 50,
    "fatal": 50,
    "error": 40,
    "warn": 30,
    "warning": 30,
    "info": 20,
    "blather": 15,
    "debug": 10,
    "trace": 5,
    "all": 1,
    "notset": 0,
    }

def logging_level(value):
    s = str(value).lower()
    if _logging_levels.has_key(s):
        return _logging_levels[s]
    else:
        v = int(s)
        if v < 0 or v > 50:
            raise ValueError("log level not in range: " + `v`)
        return v

_log_format_variables = {
    'name': '',
    'levelno': '3',
    'levelname': 'DEBUG',
    'pathname': 'apath',
    'filename': 'afile',
    'module': 'amodule',
    'lineno': 1,
    'created': 1.1,
    'asctime': 'atime',
    'msecs': 1,
    'relativeCreated': 1,
    'thread': 1,
    'message': 'amessage',
    }

def log_format(value):
    value = ctrl_char_insert(value)
    try:
        # Make sure the format string uses only names that will be
        # provided, and has reasonable type flags for each, and does
        # not expect positional args.
        value % _log_format_variables
    except (ValueError, KeyError):
        raise ValueError, 'Invalid log format string %s' % value
    return value

_control_char_rewrites = {r'\n': '\n', r'\t': '\t', r'\b': '\b',
                          r'\f': '\f', r'\r': '\r'}.items()

def ctrl_char_insert(value):
    for pattern, replacement in _control_char_rewrites:
        value = value.replace(pattern, replacement)
    return value


_marker = object()

class Factory:
    """Generic wrapper for instance construction.

    Calling the factory causes the instance to be created if it hasn't
    already been created, and returns the object.  Calling the factory
    multiple times returns the same object.

    The instance is created using the factory's create() method, which
    must be overriden by subclasses.
    """
    def __init__(self):
        self.instance = _marker

    def __call__(self):
        if self.instance is _marker:
            self.instance = self.create()
        return self.instance

    def create(self):
        raise NotImplementedError("subclasses need to override create()")


class HandlerFactory(Factory):
    def __init__(self, section):
        Factory.__init__(self)
        self.section = section

    def create_loghandler(self):
        raise NotImplementedError(
            "subclasses must override create_loghandler()")

    def create(self):
        import logging
        logger = self.create_loghandler()
        logger.setFormatter(logging.Formatter(self.section.format,
                                              self.section.dateformat))
        logger.setLevel(self.section.level)
        return logger

class FileHandlerFactory(HandlerFactory):
    def create_loghandler(self):
        # XXX this implementation should change
        from zope.app.process.loghandlers import StreamHandler, FileHandler
        path = self.section.path
        if path == "STDERR":
            return StreamHandler(sys.stderr)
        if path == "STDOUT":
            return StreamHandler(sys.stdout)
        return FileHandler(path)

_syslog_facilities = {
    "auth": 1,
    "authpriv": 1,
    "cron": 1,
    "daemon": 1,
    "kern": 1,
    "lpr": 1,
    "mail": 1,
    "news": 1,
    "security": 1,
    "syslog": 1,
    "user": 1,
    "uucp": 1,
    "local0": 1,
    "local1": 1,
    "local2": 1,
    "local3": 1,
    "local4": 1,
    "local5": 1,
    "local6": 1,
    "local7": 1,
    }

def syslog_facility(value):
    value = value.lower()
    if not _syslog_facilities.has_key(value):
        L = _syslog_facilities.keys()
        L.sort()
        raise ValueError("Syslog facility must be one of " + ", ".join(L))
    return value

class SyslogHandlerFactory(HandlerFactory):
    def create_loghandler(self):
        from zope.app.process.loghandlers import SysLogHandler
        return SysLogHandler(self.section.address.address,
                             self.section.facility)

class Win32EventLogFactory(HandlerFactory):
    def create_loghandler(self):
        from zope.app.process.loghandlers import Win32EventLogHandler
        return Win32EventLogHandler(self.section.appname)

def http_handler_url(value):
    import urlparse
    scheme, netloc, path, param, query, fragment = urlparse.urlparse(value)
    if scheme != 'http':
        raise ValueError, 'url must be an http url'
    if not netloc:
        raise ValueError, 'url must specify a location'
    if not path:
        raise ValueError, 'url must specify a path'
    q = []
    if param:
        q.append(';')
        q.append(param)
    if query:
        q.append('?')
        q.append(query)
    if fragment:
        q.append('#')
        q.append(fragment)
    return (netloc, path + ''.join(q))

def get_or_post(value):
    value = value.upper()
    if value not in ('GET', 'POST'):
        raise ValueError('method must be "GET" or "POST", instead received: '
                         + repr(value))
    return value

class HTTPHandlerFactory(HandlerFactory):
    def create_loghandler(self):
        from zope.app.process.loghandlers import HTTPHandler
        host, selector = self.section.url
        return HTTPHandler(host, selector, self.section.method)

class SMTPHandlerFactory(HandlerFactory):
    def create_loghandler(self):
        from zope.app.process.loghandlers import SMTPHandler
        host, port = self.section.smtp_server
        if not port:
            mailhost = host
        else:
            mailhost = host, port
        return SMTPHandler(mailhost, self.section.fromaddr,
                           self.section.toaddrs, self.section.subject)


class EventLogFactory(Factory):
    """
    A wrapper used to create loggers while delaying actual logger
    instance construction.  We need to do this because we may
    want to reference a logger before actually instantiating it (for example,
    to allow the app time to set an effective user).
    An instance of this wrapper is a callable which, when called, returns a
    logger object.
    """
    def __init__(self, section):
        Factory.__init__(self)
        self.level = section.level
        self.handler_factories = section.handlers

    def create(self):
        # set the logger up
        import logging
        logger = logging.getLogger("event")
        logger.handlers = []
        logger.propagate = 0
        logger.setLevel(self.level)
        if self.handler_factories:
            for handler_factory in self.handler_factories:
                handler = handler_factory()
                logger.addHandler(handler)
        else:
            from zope.app.process.loghandlers import NullHandler
            logger.addHandler(NullHandler())
        return logger


=== Added File Zope3/src/zope/app/process/event.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Process-lifetime related events.

$Id: event.py,v 1.1.2.1 2003/06/23 22:07:58 fdrake Exp $
"""

from zope.app.interfaces import event
from zope.interface import implements


class DatabaseOpened:
    implements(event.IDatabaseOpenedEvent)

    def __init__(self, database):
        self.database = database


class ProcessStarting:
    implements(event.IProcessStartingEvent)


=== Added File Zope3/src/zope/app/process/loghandlers.py ===
##############################################################################
#
# Copyright (c) 2001 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
#
##############################################################################
"""Handlers which can plug into a PEP 282 logger."""

import sys

from logging import Handler, StreamHandler
from logging.handlers import SysLogHandler
from logging.handlers import HTTPHandler, SMTPHandler
from logging.handlers import NTEventLogHandler as Win32EventLogHandler

class FileHandler(StreamHandler):
    """
    A file handler which allows for reopening of logs in favor of the
    'rollover' features of the standard PEP282 FileHandler.
    """
    def __init__(self, filename, mode="a"):
        StreamHandler.__init__(self, open(filename, mode))
        self.baseFilename = filename
        self.mode = mode

    def close(self):
        self.stream.close()

    def reopen(self):
        self.close()
        self.stream = open(self.baseFilename, self.mode)

class NullHandler(Handler):
    """
    A null handler.  Does nothing.
    """
    def emit(self, record):
        pass

    def handle(self, record):
        pass

class StartupHandler(Handler):
    """
    A handler which outputs messages to a stream but also buffers them until
    they can be flushed to a target handler.  Useful at startup before we can
    know that we can safely write to a config-specified handler.
    """
    def __init__(self, stream=None):
        Handler.__init__(self)
        if not stream:
            stream = sys.stderr
        self.stream = stream
        self.buffer = []

    def emit(self, record):
        try:
            self.buffer.append(record)
            msg = self.format(record)
            self.stream.write("%s\n" % msg)
            self.flush()
        except:
            self.handleError()

    def flush(self):
        self.stream.flush()

    def flushBufferTo(self, target):
        for record in self.buffer:
            target.handle(record)
        self.buffer = []
        
        
        
        
    


=== Added File Zope3/src/zope/app/process/main.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Functions that control how the Zope appserver knits itself together.

$Id: main.py,v 1.1.2.1 2003/06/23 22:07:58 fdrake Exp $
"""

import logging
import os
import sys
import time

from zdaemon import zdoptions

from zodb.zeo import threadedasync

from zope.app import config
from zope.app.event import publish
from zope.app.process import event
from zope.server.taskthreads import ThreadedTaskDispatcher


def main(args=None):
    # Record start times (real time and CPU time)
    t0 = time.time()
    c0 = time.clock()

    setup(args)

    t1 = time.time()
    c1 = time.clock()
    logging.info("Startup time: %.3f sec real, %.3f sec CPU", t1-t0, c1-c0)

    run()
    sys.exit(0)


def run():
    try:
        threadedasync.loop()
    except KeyboardInterrupt:
        # Exit without spewing an exception.
        pass


def setup(args=None):
    if args is None:
        args = sys.argv[1:]
    options = zdoptions.ZDOptions()
    options.schemadir = os.path.dirname(os.path.abspath(__file__))
    options.realize(args)
    options = options.configroot

    sys.setcheckinterval(options.check_interval)

    options.eventlog()

    config(options.site_definition)

    db = options.database.open()

    publish(None, event.DatabaseOpened(db))

    task_dispatcher = ThreadedTaskDispatcher()
    task_dispatcher.setThreadCount(options.threads)

    for server in options.servers:
        server.create(task_dispatcher, db)

    publish(None, event.ProcessStarting())


=== Added File Zope3/src/zope/app/process/meta.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>

  <directives namespace="http://namespaces.zope.org/startup">

    <directive name="registerRequestFactory"
               attributes="name publication request"
               handler="zope.app.process.metaconfigure.registerRequestFactory"
               />

    <directive name="registerServerType"
               attributes="name publication request"
               handler="zope.app.process.metaconfigure.registerServerType"
               />

  </directives>

</zopeConfigure>


=== Added File Zope3/src/zope/app/process/metaconfigure.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: metaconfigure.py,v 1.1.2.1 2003/06/23 22:07:58 fdrake Exp $
"""

from zope.configuration.action import Action
from zope.app.process import requestfactoryregistry
from zope.app.process import servertyperegistry
from zope.app.process.requestfactory import RequestFactory
from zope.app.process.servertype import ServerType


def registerRequestFactory(_context, name, request=None, publication=None,
                           factory=None):

    if factory:
        if request or publication:
            raise ValuesError(
                """Can't provide a request or publication (factory) if you
                provide a (request) factory""")
        request_factory = _context.resolve(factory)

    else:
        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 = True
    else:
        defaultVerbose = False

    defaultPort = int(defaultPort)

    server_type = ServerType(name, factory, requestFactory, logFactory,
                             defaultPort, defaultVerbose)

    return [
        Action(
            discriminator = name,
            callable = servertyperegistry.registerServerType,
            args = (name, server_type),
            )
        ]


=== Added File Zope3/src/zope/app/process/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.
#
##############################################################################
"""ctory.py,v 1.1.2.2 2002/04/02 02:20:40 srichter Exp $
"""

import copy
from zope.app.interfaces.startup import IRequestFactory
from zope.interface import implements

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


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


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


=== Added File Zope3/src/zope/app/process/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 2003/06/23 22:07:58 fdrake Exp $
"""
from zope.app.interfaces.startup.simpleregistry import ISimpleRegistry
from zope.app.process.simpleregistry import SimpleRegistry
from zope.app.interfaces.startup import IPublicationRequestFactoryFactory
from zope.interface import implements


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.
    """


class RequestFactoryRegistry(SimpleRegistry):
    implements(IRequestFactoryRegistry)


RequestFactoryRegistry = RequestFactoryRegistry(
    IPublicationRequestFactoryFactory)

registerRequestFactory = RequestFactoryRegistry.register
getRequestFactory = RequestFactoryRegistry.get

# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(RequestFactoryRegistry._clear)
del addCleanUp


=== Added File Zope3/src/zope/app/process/schema.xml ===
<schema>
  <!-- database and storage types -->
  <import package="zodb" />

  <!-- logging configuration -->
  <import package="zope.app.process" />

  <sectiontype name="server" datatype="zope.app.process.server.ServerFactory">
    <key name="type" required="yes" />
    <key name="address" datatype="inet-address" />
    <key name="verbose" datatype="boolean" />
  </sectiontype>

  <section type="zodb.database" name="*" required="yes"
           attribute="database" />
  <section type="eventlog" attribute="eventlog" name="*" />
  <multisection type="server" name="*" attribute="servers" />

  <key name="site-definition" default="site.zcml" />
  <key name="interrupt-check-interval" datatype="integer" default="120"
       attribute="check_interval" />
  <key name="threads" datatype="integer" default="4" />
</schema>


=== Added File Zope3/src/zope/app/process/server.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""XXX short summary goes here.

XXX longer description goes here.

$Id: server.py,v 1.1.2.1 2003/06/23 22:07:58 fdrake Exp $
"""

from zope.app.process.servertyperegistry import getServerType

class ServerFactory:

    def __init__(self, section):
        self.type = section.type
        self.address = section.address
        self.verbose = section.verbose

    def create(self, task_dispatcher, database):
        servertype = getServerType(self.type)
        # The server object self-registers with the asyncore mainloop.
        servertype.create(task_dispatcher, database,
                          self.address[1], # XXX maybe improve API
                          self.verbose)


=== Added File Zope3/src/zope/app/process/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.
#
##############################################################################
"""e.py,v 1.1.2.2 2002/04/02 02:20:40 srichter Exp $
"""

from zope.interface import Interface, implements
from zope.app.process.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


    def create(self, task_dispatcher, db, port=None, verbose=None):
        'See 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/src/zope/app/process/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 2003/06/23 22:07:58 fdrake Exp $
"""
from zope.app.interfaces.startup.simpleregistry import ISimpleRegistry
from zope.app.process.servertype import IServerType
from zope.app.process.simpleregistry import SimpleRegistry
from zope.interface import implements


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.
    """


class ServerTypeRegistry(SimpleRegistry):
    """Registry for the various Server types"""
    implements(IServerTypeRegistry)


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


=== Added File Zope3/src/zope/app/process/simpleregistry.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: simpleregistry.py,v 1.1.2.1 2003/06/23 22:07:58 fdrake Exp $
"""
from zope.app.interfaces.startup.simpleregistry import ISimpleRegistry
from types import ListType, TupleType
from zope.interface import implements
ListTypes = (TupleType, ListType)


class ZopeDuplicateRegistryEntryError(Exception):
    """
    This Error is raised when the user tries to add an object with
    a name that already exists in the registry. Therefore,
    overwriting is not allowed.
    """

    def __init__(self, name):
        """Initializes Error"""
        self.name = name

    def __str__(self):
        """Returns string representation of Error"""
        return "The name '%s' is already defined in this registry." \
               %self.name


class ZopeIllegalInterfaceError(Exception):
    """This Error is thrown, when the passed object does not implement
    the specified interface."""

    def __init__(self, name, interface):
        """Initalize Error"""
        self.name = name
        self.interface = interface

    def __str__(self):
        """Returns string representation of Error"""
        return ("The object with name " + self.name + " does not implement "
                "the interface " + self.interface.__name__ + ".")


class SimpleRegistry:
    """ """

    implements(ISimpleRegistry)

    def __init__(self, interface):
        """Initialize registry"""
        self.objects = {}
        self.interface = interface

    def _clear(self):
        self.objects.clear()

    def register(self, name, object):
        '''See ISimpleRegistry'''

        if name in self.objects.keys():
            raise ZopeDuplicateRegistryEntryError(name)

        if self.interface.isImplementedBy(object):
            self.objects[name] = object
        else:
            raise ZopeIllegalInterfaceError(name, self.interface)

        return []

    def get(self, name):
        '''See ISimpleRegistry'''
        if name in self.objects.keys():
            return self.objects[name]
        else:
            return None