Index: /main/waeup.sirp/trunk/src/waeup/sirp/utils/helpers.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/utils/helpers.py	(revision 5730)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/utils/helpers.py	(revision 5731)
@@ -5,4 +5,6 @@
 import sys
 import shutil
+import grok
+from zope.component.interfaces import IFactory
 
 def removeFileOrDirectory(filepath):
@@ -96,2 +98,98 @@
     prefix = prefix[0].upper() + prefix[1:]
     return '%s of %s' % (prefix, context.title)
+
+class FactoryBase(grok.GlobalUtility):
+    """A factory for things.
+
+    This is a baseclass for easier creation of factories. Factories
+    are utilities that are registered under a certain name and return
+    instances of certain classes when called.
+
+    In :mod:`waeup.sirp` we use factories extensively for
+    batching. While processing a batch some importer looks up a
+    factory to create real-world instances that then get filled with
+    data from imported CSV files.
+
+    To get rid of reimplementing the same stuff over and over again,
+    most notably the methods defined here, we offer this base class
+    (which will *not* be registered as a factory itself).
+
+    Real factories can then be created like this:
+
+       >>> import grok
+       >>> from waeup.sirp.utils.helpers import FactoryBase
+       >>> class MyObject(object):
+       ...   # Some class we want to get instances of.
+       ...   pass
+       >>> class MyObjectFactory(FactoryBase):
+       ...   # This is the factory for MyObject instances
+       ...   grok.name(u'waeup.sirp.factory.MyObject')
+       ...   factory = MyObject
+
+    That's it. It is essential to set the ``factory`` attribute, which
+    will determine the class of which instances should be created when
+    called. The given name must even be unique amongst all utilities
+    registered during runtime. While you can pick any name you like
+    you might want to prepend ``waeup.sirp.factory.`` to the name
+    string to make sure it does not clash with names of other
+    utilities one day.
+
+    Before all this works we have to grok the baseclass once and our
+    freshly defined factory. This executes all the component
+    registration stuff we don't want to do ourselves. In daily use
+    this is done automatically on startup of a :mod:`waeup.sirp`
+    system.
+    
+       >>> grok.testing.grok('waeup.sirp.utils.helpers')
+       >>> grok.testing.grok_component(
+       ...    'MyObjectFactory', MyObjectFactory
+       ...  )
+       True
+
+    After grokking we (and importers) can create objects without
+    knowing about the location of the real class definition, just by
+    the factory name:
+
+       >>> from zope.component import createObject
+       >>> obj = createObject('waeup.sirp.factory.MyObject')
+       >>> isinstance(obj, MyObject)
+       True
+
+    We can also use the regular utility lookups to find our new
+    factory:
+
+       >>> from zope.component import getUtility
+       >>> from zope.component.interfaces import IFactory
+       >>> factory = getUtility(
+       ...   IFactory, name='waeup.sirp.factory.MyObject'
+       ...   )
+       >>> isinstance(factory, MyObjectFactory)
+       True
+
+    And this factory generates `MyObject` instances:
+
+       >>> obj = factory()
+       >>> isinstance(obj, MyObject)
+       True
+
+    """
+    grok.baseclass() # Do not grok this class, do not register us.
+    grok.implements(IFactory)
+    # You can override any of the following attributes in derived
+    # classes. The `grok.name` setting *must* even be set to some
+    # unique value.
+    grok.name(u'waeup.Factory')
+    title = u"Create instances of ``factory``.",
+    description = u"This factory instantiates new applicant instances."
+    factory = None
+
+    def __call__(self, *args, **kw):
+        """The main factory function.
+
+        Returns an instance of the requested object.
+        """
+        return self.factory()
+
+    def getInterfaces(self):
+        # Required by IFactory
+        return implementedBy(self.factory)
