[Zope3-checkins] CVS: Zope3/src/zope/app/workflow - __init__.py:1.4 configure.zcml:1.1 definition.py:1.1 globalimportexport.py:1.1 instance.py:1.1 meta.zcml:1.1 metaconfigure.py:1.1 service.py:1.1

Ulrich Eck ueck@net-labs.de
Thu, 8 May 2003 13:27:49 -0400


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

Added Files:
	__init__.py configure.zcml definition.py globalimportexport.py 
	instance.py meta.zcml metaconfigure.py service.py 
Log Message:
Finally got it into Zope3:

Workflow has arrived!

this is a merge of the workflow package that was seperatly developed
at /Packages3/workflow.

please to a 

cvs update -dPA 

to ensure that old files/directories are deleted, otherwise you'll 
probably encounter errors when trying to run zope3

if you have problems .. send me an email ueck <at> net-labs.de

Ulrich


=== Zope3/src/zope/app/workflow/__init__.py 1.3 => 1.4 ===


=== Added File Zope3/src/zope/app/workflow/configure.zcml ===
<zopeConfigure
   xmlns='http://namespaces.zope.org/zope'
   xmlns:service='http://namespaces.zope.org/service'>


<!-- Workflow Permissions -->

<permission 
  id="zope.workflow.ManageProcessDefinitions" 
  title="Manage Workflow ProcessDefinitions" />

<permission 
  id="zope.workflow.CreateProcessInstances"
  title="Create Workflow ProcessInstances" />

<permission
  id="zope.workflow.UseProcessInstances"
  title="Use Workflow ProcessInstances" />


<!-- Workflow Service -->

<content class="zope.app.workflow.service.WorkflowService">
  <factory
      id="WorkflowService"
      permission="zope.ManageServices"
      />
  <require
      permission="zope.View"
      interface="zope.app.interfaces.workflow.IWorkflowService"
        attributes="queryConfigurations queryConfigurationsFor
                    listConfigurationNames" />
      />
  <implements 
     interface="zope.app.interfaces.annotation.IAttributeAnnotatable" 
     />
</content>

<serviceType 
  id='Workflows'
  interface='zope.app.interfaces.workflow.IWorkflowService' 
  />



<!-- Workflow Process Definition 
     This is only a generic placeholder for
     future Process Definition implementations
-->

<content class="zope.app.workflow.definition.ProcessDefinition">
  <factory
      id="ProcessDefinition"
      permission="zope.ManageServices"
      />
  <require
      permission="zope.ManageServices"
      interface="zope.app.interfaces.workflow.IProcessDefinition" 
      />
  <implements 
      interface="zope.app.interfaces.annotation.IAttributeAnnotatable" 
      />
</content>


<!-- Process Definition Configuration -->

<content class="zope.app.workflow.service.ProcessDefinitionConfiguration">
  <factory
      id="ProcessDefinitionConfiguration"
      permission="zope.ManageServices"
      />
  <require
      permission="zope.ManageServices"
      interface="zope.app.interfaces.workflow.IProcessDefinitionConfiguration"
      set_schema="zope.app.interfaces.workflow.IProcessDefinitionConfiguration"
      />
  <require
      permission="zope.ManageServices"
      interface="zope.app.interfaces.container.IAddNotifiable"
      />
  <require
      permission="zope.ManageServices"
      interface="zope.app.interfaces.container.IDeleteNotifiable"
      />
</content>


<!-- Process Instance Container -->

<content class="zope.app.workflow.definition.ProcessDefinitionElementContainer">

  <implements interface="zope.app.interfaces.container.IContentContainer" />

  <implements
     interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
     />

  <require
      permission="zope.View"
      interface="zope.app.interfaces.container.IReadContainer"
      />

  <require
      permission="zope.workflow.ManageProcessDefinitions"
      interface="zope.app.interfaces.container.IWriteContainer"
      />
</content>

<adapter factory="zope.app.workflow.instance.ProcessInstanceContainerAdapter"
         provides="zope.app.interfaces.workflow.IProcessInstanceContainer"
         for="zope.app.interfaces.annotation.IAnnotatable" />

<!-- Workflow Import/Export Utility -->

<utility
    component=".globalimportexport.globalImportExport" 
    provides="zope.app.interfaces.workflow.IProcessDefinitionImportExport"
    permission="zope.workflow.ManageProcessDefinitions" 
    />

<include package=".stateful" />

</zopeConfigure>


=== Added File Zope3/src/zope/app/workflow/definition.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.
#
##############################################################################
"""Implementation of workflow process definition.

$Id: definition.py,v 1.1 2003/05/08 17:27:18 jack-e Exp $
"""
__metaclass__ = type

from types import StringTypes
from persistence import Persistent
from persistence.dict import PersistentDict
from zope.proxy.context import ContextAware, getWrapperContainer
from zope.app.interfaces.workflow \
     import IProcessDefinition, IProcessDefinitionElementContainer


class ProcessDefinition(Persistent):

    __doc__ = IProcessDefinition.__doc__
    
    __implements__ = IProcessDefinition

    name = None

    ############################################################
    # Implementation methods for interface
    # zope.app.interfaces.workflow.IProcessDefinition

    def createProcessInstance(self, definition_name):
        return None

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





class ProcessDefinitionElementContainer(ContextAware, Persistent):
    """ See IProcessDefinitionElementContainer.
    """

    __implements__ = IProcessDefinitionElementContainer

    def __init__(self):
        super(ProcessDefinitionElementContainer, self).__init__()
        self.__data = PersistentDict()

    def keys(self):
        '''See interface IProcessDefinitionElementContainer'''
        return self.__data.keys()
 
    def __iter__(self):
        return iter(self.__data.keys())
 
    def __getitem__(self, key):
        '''See interface IProcessDefinitionElementContainer'''
        return self.__data[key]
 
    def get(self, key, default=None):
        '''See interface IProcessDefinitionElementContainer'''
        return self.__data.get(key, default)
 
    def values(self):
        '''See interface IProcessDefinitionElementContainer'''
        return self.__data.values()
 
    def __len__(self):
        '''See interface IProcessDefinitionElementContainer'''
        return len(self.__data)
 
    def items(self):
        '''See interface IProcessDefinitionElementContainer'''
        return self.__data.items()
 
    def __contains__(self, key):
        '''See interface IProcessDefinitionElementContainer'''
        return self.__data.has_key(key)
 
    has_key = __contains__
 
    def setObject(self, key, object):
        '''See interface IProcessDefinitionElementContainer'''
        bad = False
        if isinstance(key, StringTypes):
            try:
                unicode(key)
            except UnicodeError:
                bad = True
        else:
            bad = True
        if bad:
            raise TypeError("'%s' is invalid, the key must be an "
                            "ascii or unicode string" % key)
        if len(key) == 0:
            raise ValueError("The key cannot be an empty string")
        self.__data[key] = object
        return key
                
    def __delitem__(self, key):
        '''See interface IProcessDefinitionElementContainer'''
        del self.__data[key]


    def getProcessDefinition(self):
        return getWrapperContainer(self)


=== Added File Zope3/src/zope/app/workflow/globalimportexport.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.
#
##############################################################################
"""ProcessDefinition Import Export Utility

$Id: globalimportexport.py,v 1.1 2003/05/08 17:27:18 jack-e Exp $
"""
__metaclass__ = type

from zope.interface.implementor import ImplementorRegistry
from zope.interface._flatten import _flatten
from zope.proxy.introspection import removeAllProxies
from zope.app.interfaces.workflow import IProcessDefinition
from zope.app.interfaces.workflow import IGlobalProcessDefinitionImportExport

from StringIO import StringIO

class ImportExportUtility:

    __implements__ = IGlobalProcessDefinitionImportExport


    def __init__(self):
        self._importers = ImplementorRegistry()
        self._exporters = ImplementorRegistry()
        
    _clear = __init__

    # IProcessDefinitionImportExport
    
    def importProcessDefinition(self, context, data):
        """Import a Process Definition
        """
        if not hasattr(data, "read"):
            data = StringIO(data)

        for iface, factory in self._importers.getRegisteredMatching():
            if iface.extends(IProcessDefinition):
                imp = factory()
                data.seek(0)
                if imp.canImport(context, data):
                    data.seek(0)
                    return imp.doImport(context, data)

        raise ValueError, 'No Importer can handle that information'

    def exportProcessDefinition(self, context, process_definition):
        """Export a Process Definition
        """
        clean_pd = removeAllProxies(process_definition)
        interfaces = filter(lambda x: x.extends(IProcessDefinition),
                           _flatten(clean_pd.__implements__))
        for interface in interfaces:
            factory = self._exporters.get(interface)
            if factory is not None:
                return factory().doExport(context, clean_pd)
        raise TypeError, "object doesn't implement IProcessDefinition"


    # IGlobalProcessDefinitionImportExport

    def addImportHandler(self, interface, factory):
        """add Import Handler for ProcessDefinition
        """
        self._importers.register(interface, factory)

    def addExportHandler(self, interface, factory):
        """add Export Handler for ProcessDefinition
        """
        self._exporters.register(interface, factory)

    

globalImportExport = ImportExportUtility()


_clear = globalImportExport._clear

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


=== Added File Zope3/src/zope/app/workflow/instance.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.
# 
##############################################################################
"""Implementation of workflow process instance.

$Id: instance.py,v 1.1 2003/05/08 17:27:18 jack-e Exp $
"""
__metaclass__ = type

from types import StringTypes
from persistence import Persistent
from persistence.dict import PersistentDict
from zope.proxy.context import ContextWrapper
from zope.proxy.introspection import removeAllProxies

from zope.app.interfaces.annotation import IAnnotatable, IAnnotations
from zope.app.interfaces.workflow \
     import IProcessInstance, IProcessInstanceContainer

from zope.component import getAdapter

# XXX should an Instance be persistent by default ???
class ProcessInstance:

    __doc__ = IProcessInstance.__doc__

    __implements__ =  IProcessInstance

    def __init__(self, pd_name):
        self._pd_name = pd_name
        self._status = None
  
    
    ############################################################
    # Implementation methods for interface
    # zope.app.interfaces.workflow.IProcessInstance


    processDefinitionName = property(lambda self: self._pd_name)

    status = property(lambda self: self._status)


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


    ## should probably have a method "getProcessDefinition"








_marker = object()

WFKey = "zope.app.worfklow.ProcessInstanceContainer"

class ProcessInstanceContainerAdapter:

    __implements__ = IProcessInstanceContainer

    __used_for__ = IAnnotatable

    def __init__(self, context):
        self.context = context
        annotations = getAdapter(context, IAnnotations)
        wfdata = annotations.get(WFKey)
        if not wfdata:
            wfdata = PersistentDict()
            annotations[WFKey] = wfdata
        self.wfdata = wfdata

    def __getitem__(self, key):
        "See IProcessInstanceContainer"
        value = self.wfdata[key]
        return ContextWrapper(value, self.context, name=key)
 
    def get(self, key, default=None):
        "See IProcessInstanceContainer"
        value = self.wfdata.get(key, _marker)
        if value is not _marker:
            return ContextWrapper(value, self.context, name=key)
        else:
            return default
 
    def __contains__(self, key):
        "See IProcessInstanceContainer"
        return key in self.wfdata
 
 
    def values(self):
        "See IProcessInstanceContainer"
        container = self.wfdata
        result = []
        for key, value in container.items():
            result.append(ContextWrapper(value, self.context, name=key))
        return result
 
    def keys(self):
        "See IProcessInstanceContainer"
        return self.wfdata.keys()
 
    def __len__(self):
        "See IProcessInstanceContainer"
        return len(self.wfdata)
 
    def items(self):
        "See IProcessInstanceContainer"
        container = self.wfdata
        result = []
        for key, value in container.items():
            result.append((key, ContextWrapper(value, self.context, name=key)))
        return result
    
    def setObject(self, key, object):
        "See IProcessInstanceContainer"
 
        if not isinstance(key, StringTypes):
            raise TypeError("Item name is not a string.")
 
        container = self.wfdata
        object = removeAllProxies(object)
        container[key] = object
        # publish event ??
        return key
 
 
    def __delitem__(self, key):
        "See IZopeWriteContainer"
        container = self.wfdata
        # publish event ?
        del container[key]
        return key

    def __iter__(self):
        '''See interface IReadContainer'''
        return iter(self.context)



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

    <directive name="importHandler" 
               handler=".metaconfigure.importHandlerDirective">

      <description>
        Register an Import Handler, that is able to load a XML
        Representation of a ProcessDefinition and create
        a persistent Instance for it.
      </description>


      <attribute name="for" required="yes">
        <description>
              The interface of the process defintion, 
              this handler can load. 
          </description>
      </attribute>

      <attribute name="factory">
        <description>
              The factory for the instance that implements the handler. 
          </description>
      </attribute>

    </directive>

    <directive name="exportHandler" 
               handler=".metaconfigure.exportHandlerDirective">

      <description>
        Register an Export Handler, that is able to save a XML
        Representation of a ProcessDefinition from a given object.
      </description>


      <attribute name="for" required="yes">
        <description>
              The interface of the process defintion, 
              this handler can save. 
          </description>
      </attribute>

      <attribute name="factory">
        <description>
              The factory for the instance that implements the handler. 
          </description>
      </attribute>

    </directive>

  </directives>

</zopeConfigure>


=== Added File Zope3/src/zope/app/workflow/metaconfigure.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.
#
##############################################################################
"""ProcessDefinition Import Export Utility

$Id: metaconfigure.py,v 1.1 2003/05/08 17:27:18 jack-e Exp $
"""
__metaclass__ = type

from zope.configuration.action import Action
from globalimportexport import globalImportExport

#

def importHandlerDirective(_context, interface, factory):
    interface = _context.resolve(interface)
    factory = _context.resolve(factory)
    return [
        Action(
              discriminator = ('workflow','importHandler', interface),
              callable = addImportHandler,
              args = (interface, factory)
              )
        ]


def exportHandlerDirective(_context, interface, factory):
    interface = _context.resolve(interface)
    factory = _context.resolve(factory)
    return [
        Action(
              discriminator = ('workflow','exportHandler', interface),
              callable = addExportHandler,
              args = (interface, factory)
              )
        ]




def addImportHandler(interface, factory):
    globalImportExport.addImportHandler(interface, factory)

def addExportHandler(interface, factory):
    globalImportExport.addExportHandler(interface, factory)



=== Added File Zope3/src/zope/app/workflow/service.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.
#
##############################################################################
"""Workflow service implementation.

Revision information:
$Id: service.py,v 1.1 2003/05/08 17:27:18 jack-e Exp $
"""
__metaclass__ = type

from persistence import Persistent

from zope.proxy.context import ContextMethod, ContextWrapper

from zope.component import getAdapter
from zope.app.component.nextservice import queryNextService
from zope.app.interfaces.services.configuration \
        import INameComponentConfigurable
from zope.app.services.configuration import NameComponentConfigurable

from zope.app.services.configuration import NamedComponentConfiguration
from zope.app.services.configuration import ConfigurationStatusProperty
from zope.app.interfaces.services.configuration import IUseConfiguration
from zope.app.traversing import traverse, getPath

from zope.app.interfaces.services.service import ISimpleService
from zope.app.interfaces.workflow import IProcessDefinitionConfiguration
from zope.app.interfaces.workflow import IProcessDefinition
from zope.app.interfaces.workflow import IWorkflowService


class ILocalWorkflowService(IWorkflowService, INameComponentConfigurable):
    """A Local WorkflowService.
    """


class WorkflowService(Persistent, NameComponentConfigurable):

    __doc__ = IWorkflowService.__doc__

    __implements__ = ILocalWorkflowService, ISimpleService 
                     

    ############################################################
    # Implementation methods for interface
    # zope.app.interfaces.workflow.IWorkflowService

    def getProcessDefinitionNames(self):
        'See IWorkflowService'
        definition_names = {}
        for name in self.listConfigurationNames():
            registry = self.queryConfigurations(name)
            if registry.active() is not None:
                definition_names[name] = 0
        service = queryNextService(self, "Workflows")
        if service is not None:
            for name in service.getProcessDefinitionNames():
                definition_names[name] = 0
        return definition_names.keys()

    getProcessDefinitionNames = ContextMethod(getProcessDefinitionNames)


    def getProcessDefinition(self, name):
        'See IWorkflowService'
        pd = self.queryActiveComponent(name)
        if pd is not None:
            return ContextWrapper(pd, self, name=name)
        service = queryNextService(self, "Workflows")
        if service is not None:
            return service.getProcessDefinition(name)
        raise KeyError, name

    getProcessDefinition = ContextMethod(getProcessDefinition)


    def queryProcessDefinition(self, name, default=None):
        'See IWorkflowService'
        try:
            return self.getProcessDefinition(name)
        except KeyError:
            return default

    queryProcessDefinition = ContextMethod(queryProcessDefinition)


    def createProcessInstance(self, definition_name):
        pd = self.getProcessDefinition(definition_name)
        return pd.createProcessInstance(definition_name)

    createProcessInstance = ContextMethod(createProcessInstance)

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




class ProcessDefinitionConfiguration(NamedComponentConfiguration):

    __doc__ = IProcessDefinitionConfiguration.__doc__

    __implements__ = (IProcessDefinitionConfiguration,
                      NamedComponentConfiguration.__implements__)

    status = ConfigurationStatusProperty('Workflows')


    def getInterface(self):
        return IProcessDefinition

    # The following hooks are called only if we implement
    # IAddNotifiable and IDeleteNotifiable.

    def afterAddHook(self, configuration, container):
        """Hook method will call after an object is added to container.

        Defined in IAddNotifiable.
        """
        super(ProcessDefinitionConfiguration, self).afterAddHook(configuration,
                                                                 container)
        pd = configuration.getComponent()
        adapter = getAdapter(pd, IUseConfiguration)
        adapter.addUsage(getPath(configuration))


    def beforeDeleteHook(self, configuration, container):
        """Hook method will call before object is removed from container.

        Defined in IDeleteNotifiable.
        """
        pd = configuration.getComponent()
        adapter = getAdapter(pd, IUseConfiguration)
        adapter.removeUsage(getPath(configuration))
        super(ProcessDefinitionConfiguration, self).beforeDeleteHook(configuration,
                                                                     container)