Index: /main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/interfaces.py
===================================================================
--- /main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/interfaces.py	(revision 9096)
+++ /main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/interfaces.py	(revision 9097)
@@ -19,4 +19,5 @@
 import re
 import codecs
+import zc.async.interfaces
 import zope.i18nmessageid
 from datetime import datetime
@@ -29,5 +30,6 @@
 from zope.component import getUtility
 from zope.component.interfaces import IObjectEvent
-from zope.container.interfaces import INameChooser
+from zope.configuration.fields import Path
+from zope.container.interfaces import INameChooser, IContainer
 from zope.interface import Interface, Attribute
 from zope.schema.interfaces import IObject
@@ -39,4 +41,6 @@
 DELETION_MARKER = 'XXX'
 IGNORE_MARKER = '<IGNORE>'
+WAEUP_KEY = 'waeup.kofa'
+VIRT_JOBS_CONTAINER_NAME = 'jobs'
 
 CREATED = 'created'
@@ -49,4 +53,15 @@
 REGISTERED = 'courses registered'
 VALIDATED = 'courses validated'
+
+#: A dict giving job status as tuple (<STRING>, <TRANSLATED_STRING>),
+#: the latter for UI purposes.
+JOB_STATUS_MAP = {
+    zc.async.interfaces.NEW: ('new', _('new')),
+    zc.async.interfaces.COMPLETED: ('completed', _('completed')),
+    zc.async.interfaces.PENDING: ('pending', _('pending')),
+    zc.async.interfaces.ACTIVE: ('active', _('active')),
+    zc.async.interfaces.ASSIGNED: ('assigned', _('assigned')),
+    zc.async.interfaces.CALLBACKS: ('callbacks', _('callbacks')),
+    }
 
 #default_rest_frontpage = u'' + codecs.open(os.path.join(
@@ -1081,5 +1096,5 @@
         """
 
-from zope.configuration.fields import Path
+
 class IDataCenterConfig(Interface):
     path = Path(
@@ -1090,2 +1105,97 @@
         )
 
+#
+# Asynchronous job handling and related
+#
+class IJobManager(IKofaObject):
+    """A manager for asynchronous running jobs (tasks).
+    """
+    def put(job, site=None):
+        """Put a job into task queue.
+
+        If no `site` is given, queue job in context of current local
+        site.
+
+        Returns a job_id to identify the put job. This job_id is
+        needed for further references to the job.
+        """
+
+    def jobs(site=None):
+        """Get an iterable of jobs stored.
+        """
+
+    def get(job_id, site=None):
+        """Get the job with id `job_id`.
+
+        For the `site` parameter see :meth:`put`.
+        """
+
+    def remove(job_id, site=None):
+        """Remove job with `job_id` from stored jobs.
+        """
+
+    def start_test_job(site=None):
+        """Start a test job.
+        """
+
+class IProgressable(Interface):
+    """A component that can indicate its progress status.
+    """
+    percent = schema.Float(
+        title = u'Percent of job done already.',
+        )
+
+class IJobContainer(IContainer):
+    """A job container contains IJob objects.
+    """
+
+class IExportJob(zc.async.interfaces.IJob):
+    def __init__(site, exporter_name):
+        pass
+
+class IExportJobContainer(Interface):
+    """A component that contains (maybe virtually) export jobs.
+    """
+    def start_export_job(exporter_name, user_id):
+        """Start asynchronous export job.
+
+        `exporter_name` is the name of an exporter utility to be used.
+
+        `user_id` is the ID of the user that triggers the export.
+
+        The job_id is stored along with exporter name and user id in a
+        persistent list.
+
+        Returns the job ID of the job started.
+        """
+
+    def get_running_export_jobs(user_id=None):
+        """Get export jobs for user with `user_id` as list of tuples.
+
+        Each tuples holds ``<job_id>, <exporter_name>, <user_id>`` in
+        that order. The ``<exporter_name>`` is the utility name of the
+        used exporter.
+
+        If `user_id` is ``None``, all running jobs are returned.
+        """
+
+    def get_export_jobs_status(user_id=None):
+        """Get running/completed export jobs for `user_id` as list of tuples.
+
+        Each tuple holds ``<raw status>, <status translated>,
+        <exporter title>`` in that order, where ``<status
+        translated>`` and ``<exporter title>`` are translated strings
+        representing the status of the job and the human readable
+        title of the exporter used.
+        """
+
+    def delete_export_entry(entry):
+        """Delete the export denoted by `entry`.
+
+        Removes `entry` from the local `running_exports` list and also
+        removes the regarding job via the local job manager.
+
+        `entry` is a tuple ``(<job id>, <exporter name>, <user id>)``
+        as created by :meth:`start_export_job` or returned by
+        :meth:`get_running_export_jobs`.
+        """
