From e184ed92a7ef194539003e937cef886446742f36 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sun, 30 Nov 2008 13:42:54 +0000 Subject: [PATCH] provide basic job managemen git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3018 fd906abe-77d9-0310-91a1-e0d9ade77398 --- CHANGES.txt | 6 ++++ organize/configure.zcml | 1 + organize/job/README.txt | 71 +++++++++++++++++++++++++++++++++++++ organize/job/__init__.py | 3 ++ organize/job/base.py | 40 +++++++++++++++++++++ organize/job/browser.py | 56 +++++++++++++++++++++++++++++ organize/job/configure.zcml | 15 ++++++++ organize/job/tests.py | 26 ++++++++++++++ 8 files changed, 218 insertions(+) create mode 100644 organize/job/README.txt create mode 100644 organize/job/__init__.py create mode 100644 organize/job/base.py create mode 100644 organize/job/browser.py create mode 100644 organize/job/configure.zcml create mode 100755 organize/job/tests.py diff --git a/CHANGES.txt b/CHANGES.txt index 0a4e071..ed72985 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,4 +6,10 @@ $Id$ 0.9 --- +- basic job management: a job executor view calls job managers specified + by loops root option ``organize.job.managers`` +- allow ``__getitem__`` on Loops and ViewManager, this is a prerequisite for + using virtual hosts over more than one path element (e.g. leading to + views/home) on protected sites; this also allows calling of job processiong + views via wget without login credentials - add definition of loops package version (see loops/version.py) diff --git a/organize/configure.zcml b/organize/configure.zcml index 2ee6835..499b27c 100644 --- a/organize/configure.zcml +++ b/organize/configure.zcml @@ -68,6 +68,7 @@ + diff --git a/organize/job/README.txt b/organize/job/README.txt new file mode 100644 index 0000000..f6d99c7 --- /dev/null +++ b/organize/job/README.txt @@ -0,0 +1,71 @@ +=============================================================== +loops - Linked Objects for Organization and Processing Services +=============================================================== + + ($Id$) + +Let's do some basic setup + + >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown + >>> site = placefulSetUp(True) + >>> from zope import component, interface + +and set up a simple loops site with a concept manager and some concepts +(with all the type machinery, what in real life is done via standard +ZCML setup): + + >>> from loops.organize.setup import SetupManager + >>> component.provideAdapter(SetupManager, name='organize') + + >>> from loops.tests.setup import TestSite + >>> t = TestSite(site) + >>> concepts, resources, views = t.setup() + >>> loopsRoot = site['loops'] + +Let's also set up logging in a way that we get notified about problems. + + >>> import sys + >>> from logging import getLogger, StreamHandler + >>> getLogger('loops.organize.job').addHandler(StreamHandler(sys.stdout)) + + +Execute Jobs via a cron Call +============================ + + >>> from zope.publisher.browser import TestRequest + >>> from loops.organize.job.browser import Executor + +The executor is a view that will be called by calling its ``processJobs`` +method. As we haven't yet defined any job managers nothing happens. + + >>> executor = Executor(loopsRoot, TestRequest()) + >>> executor.processJobs() + +We now register a job manager via an options setting on the loops root object. +As the corresponding job manager is not yet defined an registered a +warning is issued. + + >>> loopsRoot.options = ['organize.job.managers:loops_notifier'] + >>> executor = Executor(loopsRoot, TestRequest()) + >>> executor.processJobs() + Job manager 'loops_notifier' not found. + +So let's now define a job manager class and register it as an adapter for +the loops root object. + + >>> from loops.organize.job.base import JobManager + >>> class Notifier(JobManager): + ... def process(self): + ... print 'processing...' + + >>> component.provideAdapter(Notifier, name='loops_notifier') + >>> loopsRoot.options = ['organize.job.managers:loops_notifier'] + >>> executor = Executor(loopsRoot, TestRequest()) + >>> executor.processJobs() + processing... + + +Fin de partie +============= + + >>> placefulTearDown() diff --git a/organize/job/__init__.py b/organize/job/__init__.py new file mode 100644 index 0000000..38314f3 --- /dev/null +++ b/organize/job/__init__.py @@ -0,0 +1,3 @@ +""" +$Id$ +""" diff --git a/organize/job/base.py b/organize/job/base.py new file mode 100644 index 0000000..1737694 --- /dev/null +++ b/organize/job/base.py @@ -0,0 +1,40 @@ +# +# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +Base class(es) for job management. + +$Id$ +""" + +from zope import component, interface + +from cybertools.organize.interfaces import IJobManager +from loops.interfaces import ILoops + + +class JobManager(object): + + interface.implements(IJobManager) + component.adapts(ILoops) + + def __init__(self, context): + self.context = context + + def process(self): + raise NotImplementedError("Method 'process' has to be implementd by subclass.") diff --git a/organize/job/browser.py b/organize/job/browser.py new file mode 100644 index 0000000..d800d51 --- /dev/null +++ b/organize/job/browser.py @@ -0,0 +1,56 @@ +# +# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +Definition of view classes and other browser related stuff for job management. + +$Id$ +""" + +from logging import getLogger +from zope import component +from zope.cachedescriptors.property import Lazy + +from cybertools.meta.interfaces import IOptions +from cybertools.organize.interfaces import IJobManager + + +class Executor(object): + """ A view whose processJobs method should be called via cron + wget + in order to execute all jobs that are found. + """ + + def __init__(self, context, request): + self.context = context + self.request = request + + @Lazy + def options(self): + return IOptions(self.context) + + @Lazy + def logger(self): + return getLogger('loops.organize.job') + + def processJobs(self): + for name in self.options('organize.job.managers', []): + manager = component.queryAdapter(self.context, IJobManager, name=name) + if manager is None: + self.logger.warn("Job manager '%s' not found." % name) + else: + manager.process() diff --git a/organize/job/configure.zcml b/organize/job/configure.zcml new file mode 100644 index 0000000..1572dce --- /dev/null +++ b/organize/job/configure.zcml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/organize/job/tests.py b/organize/job/tests.py new file mode 100755 index 0000000..8a5ea94 --- /dev/null +++ b/organize/job/tests.py @@ -0,0 +1,26 @@ +# $Id$ + +import os +import unittest, doctest +from zope.testing.doctestunit import DocFileSuite + + +testDir = os.path.join(os.path.dirname(__file__), 'testdata') + + +class Test(unittest.TestCase): + "Basic tests for the loops.organize.job package." + + def testBasics(self): + pass + + +def test_suite(): + flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS + return unittest.TestSuite(( + unittest.makeSuite(Test), + DocFileSuite('README.txt', optionflags=flags), + )) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite')