[Checkins] SVN: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/ Zope 2.10 compatible version. MultiProcessor does not work as expected yet, but single processor or job management page works.

Radim Novotny novotny.radim at gmail.com
Wed May 14 04:34:23 EDT 2008


Log message for revision 86722:
  Zope 2.10 compatible version. MultiProcessor does not work as expected yet, but single processor or job management page works. 
  

Changed:
  U   lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py
  U   lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml
  U   lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py
  A   lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml
  U   lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml
  U   lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py
  U   lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py

-=-
Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py	2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/__init__.py	2008-05-14 08:34:23 UTC (rev 86722)
@@ -1,2 +1,31 @@
 # Make a package.
 from lovely.remotetask.service import TaskService
+
+try:
+    from Products.Five.site.interfaces import IFiveUtilityRegistry
+    ZOPE2=True
+except ImportError:
+    ZOPE2=False
+    
+# This is implemented as IDatabaseOpenedEvent in Zope 3
+if ZOPE2:
+    from lovely.remotetask.service import TaskService, getAutostartServiceNames
+    from lovely.remotetask.interfaces import ITaskService
+    from zope.component import getUtilitiesFor
+    from zope.app.component.hooks import getSite
+    from Products.CMFCore.interfaces._content import ISiteRoot
+
+    def initialize(context):
+        # dirty trick, but it works
+        app = context._ProductContext__app
+        services = getAutostartServiceNames()
+
+        for service in services:
+            site_name, service_name = service.split('@')
+            if site_name:
+                site = getattr(app, site_name, None)
+                if site:
+                    registry = site.getSiteManager()
+                    service = registry.queryUtility(ITaskService, name=service_name)
+                    if ITaskService.providedBy(service) and not service.isProcessing():
+                        service.startProcessing()

Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml	2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/configure.zcml	2008-05-14 08:34:23 UTC (rev 86722)
@@ -1,5 +1,6 @@
 <configure
     xmlns="http://namespaces.zope.org/browser"
+    xmlns:zcml="http://namespaces.zope.org/zcml"
     xmlns:zope="http://namespaces.zope.org/zope">
 
   <resourceDirectory
@@ -8,6 +9,7 @@
       />
 
   <addMenuItem
+      zcml:condition="not-installed Products.Five"
       class="..service.TaskService"
       title="Remote Task Service"
       description="A Remote Task Service"
@@ -15,6 +17,7 @@
       />
 
   <page
+      zcml:condition="not-installed Products.Five"
       name="jobs.html"
       for="..interfaces.ITaskService"
       class=".service.JobsOverview"
@@ -23,6 +26,7 @@
       />
 
   <page
+      zcml:condition="not-installed Products.Five"
       name="detail"
       for="..interfaces.IJob"
       permission="zope.ManageContent"
@@ -30,6 +34,7 @@
       />
 
   <page
+      zcml:condition="not-installed Products.Five"
       name="detail"
       for="..interfaces.ICronJob"
       permission="zope.Public"
@@ -37,6 +42,7 @@
       />
 
   <page
+      zcml:condition="not-installed Products.Five"
       name="editjob"
       for="..interfaces.ICronJob"
       permission="zope.ManageContent"
@@ -45,6 +51,7 @@
       />
 
   <page
+      zcml:condition="not-installed Products.Five"
       name="addcronjob.html"
       for="..interfaces.ITaskService"
       class=".job.AddCronJob"
@@ -61,4 +68,6 @@
       permission="zope.Public"
       />
 
+  <include file="zope210compat.zcml" zcml:condition="installed Products.Five" /> 
+
 </configure>

Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py	2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/service.py	2008-05-14 08:34:23 UTC (rev 86722)
@@ -35,6 +35,12 @@
     # But still support the old location if we can't get it from the new:
     from zope.app.session.interfaces import ISession
 
+try:
+    from Products import Five
+    ZOPE2 = True
+except ImportError:
+    ZOPE2 = False
+
 from zope.app.pagetemplate import ViewPageTemplateFile
 from zope.app.container.contained import contained
 
@@ -202,9 +208,13 @@
 
     def renderCell(self, item, formatter):
         date = self.getter(item, formatter)
-        dformat = formatter.request.locale.dates.getFormatter(
-            'dateTime', 'medium')
-        return date and dformat.format(date) or '[not set]'
+        if not ZOPE2:
+            dformat = formatter.request.locale.dates.getFormatter(
+                'dateTime', 'medium')
+            return date and dformat.format(date) or '[not set]'
+        else:
+            # request has no 'locale' 
+            return date or '[not set]'
 
     def getSortKey(self, item, formatter):
         return self.getter(item, formatter)
@@ -396,6 +406,14 @@
         return self.template()
 
 from zope.publisher.interfaces import IPublishTraverse
+try:
+    from Products import Five
+    from Acquisition import aq_base, aq_inner
+    ZOPE2 = True
+    del Five
+except ImportError:
+    ZOPE2 = False
+    
 
 class ServiceJobTraverser(object):
     zope.interface.implements(IPublishTraverse)
@@ -415,5 +433,10 @@
                                                 name=name)
         if view is not None:
             return view
-        raise NotFound(self.context, name, request)
+        else:
+            if ZOPE2:
+                obj = getattr(aq_base(aq_inner(self.context)), name, None)
+                if obj is not None:
+                    return obj
+            raise NotFound(self.context, name, request)
 

Added: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml	                        (rev 0)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/browser/zope210compat.zcml	2008-05-14 08:34:23 UTC (rev 86722)
@@ -0,0 +1,41 @@
+<configure
+    xmlns="http://namespaces.zope.org/browser"
+    xmlns:zcml="http://namespaces.zope.org/zcml"
+    xmlns:zope="http://namespaces.zope.org/zope">
+
+  <page
+      name="jobs.html"
+      for="..interfaces.ITaskService"
+      class=".service.JobsOverview"
+      permission="zope.Public"
+      />
+
+  <page
+      name="detail"
+      for="..interfaces.IJob"
+      permission="zope.Public"
+      class=".job.JobDetail"
+      />
+
+  <page
+      name="detail"
+      for="..interfaces.ICronJob"
+      permission="zope.Public"
+      class=".job.CronJobDetail"
+      />
+
+  <page
+      name="editjob"
+      for="..interfaces.ICronJob"
+      permission="zope.Public"
+      class=".job.CronJobEdit"
+      />
+
+  <page
+      name="addcronjob.html"
+      for="..interfaces.ITaskService"
+      class=".job.AddCronJob"
+      permission="zope.Public"
+      />
+
+</configure>

Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml	2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/configure.zcml	2008-05-14 08:34:23 UTC (rev 86722)
@@ -1,5 +1,7 @@
 <configure
     xmlns="http://namespaces.zope.org/zope"
+    xmlns:zcml="http://namespaces.zope.org/zcml"
+    xmlns:five="http://namespaces.zope.org/five"
     i18n_domain="lovely.remotetask">
 
   <class class=".service.TaskService">
@@ -38,8 +40,9 @@
       factory=".task.EchoTask"
       name="echo" />
 
-  <include file="xmlrpc.zcml" />
-
+  <include zcml:condition="not-installed Products.Five" file="xmlrpc.zcml" />
+  <five:registerPackage zcml:condition="installed Products.Five" package="." initialize=".initialize" />
+  
   <include package=".browser" />
   <include package=".generations" />
 

Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py	2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/processor.py	2008-05-14 08:34:23 UTC (rev 86722)
@@ -28,6 +28,15 @@
 from zope.security.proxy import removeSecurityProxy
 from zope.traversing.api import traverse
 
+try:
+    from ZPublisher.HTTPRequest import HTTPRequest
+    from ZPublisher.HTTPResponse import HTTPResponse
+    import ZPublisher
+    from types import StringType
+    ZOPE2=True
+except ImportError:
+    ZOPE2=False
+
 from lovely.remotetask import interfaces
 
 THREAD_STARTUP_WAIT = 0.05
@@ -92,7 +101,7 @@
             log.error('Processor: ``%s()`` caused an error!' %method)
             log.exception(error)
             return errorValue is ERROR_MARKER and error or errorValue
-
+            
     def processNext(self, jobid=None):
         return self.call('processNext', args=(None, jobid))
 
@@ -104,7 +113,38 @@
             if not result:
                 time.sleep(self.waitTime)
 
+class SimpleZope2Processor(SimpleProcessor):
+    """ SimpleProcessor for Zope2 """
+    
+    zope.interface.implements(interfaces.IProcessor)
 
+    def call(self, method, args=(), errorValue=ERROR_MARKER):
+        path = [method] + self.servicePath[:]
+        path.reverse()
+        response = HTTPResponse()
+        env = { 'SERVER_NAME': 'dummy',
+                'SERVER_PORT': '8080',
+                'PATH_INFO': '/' + '/'.join(path) }
+        request = HTTPRequest(None, env, response)
+        conn = self.db.open()
+        root = conn.root()
+        request['PARENTS'] = [root[ZopePublication.root_name]]
+        try:
+            try:
+                ZPublisher.Publish.publish(request,'Zope2', [None])
+            except Exception, error:
+                # This thread should never crash, thus a blank except
+                log.error('Processor: ``%s()`` caused an error!' %method)
+                log.exception(error)
+                return errorValue is ERROR_MARKER and error or errorValue
+        finally:
+            request.close()
+            conn.close()
+            if not request.response.body:
+                time.sleep(1)
+            else:
+                return request.response.body
+
 class MultiProcessor(SimpleProcessor):
     """Multi-threaded Job Processor
 
@@ -150,3 +190,34 @@
                 thread.start()
                 # Give the thread some time to start up:
                 time.sleep(THREAD_STARTUP_WAIT)
+
+class MultiZope2Processor(MultiProcessor, SimpleZope2Processor):
+    """Multi-threaded Job Processor
+
+    This processor can work on multiple jobs at the same time.
+    
+    WARNING: This still does not work correctly in Zope2
+    """
+    zope.interface.implements(interfaces.IProcessor)
+
+    def __init__(self, *args, **kwargs):
+        self.maxThreads = kwargs.pop('maxThreads', 5)
+        super(MultiZope2Processor, self).__init__(*args, **kwargs)
+        self.threads = []
+
+    def hasJobsWaiting(self):
+        value = self.call('hasJobsWaiting', errorValue=False)
+        if isinstance(value, StringType):
+            if value == 'True':
+                return True
+            else:
+                return False
+        return value
+
+    def claimNextJob(self):
+        value = self.call('claimNextJob', errorValue=None)
+        try:
+            value = int(value)
+        except ValueError:
+            pass
+        return value

Modified: lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py
===================================================================
--- lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py	2008-05-14 08:11:14 UTC (rev 86721)
+++ lovely.remotetask/branches/port-for-zope210/src/lovely/remotetask/service.py	2008-05-14 08:34:23 UTC (rev 86722)
@@ -27,7 +27,6 @@
 from BTrees.IOBTree import IOBTree
 from zope import component
 from zope.app import zapi
-from zope.app.appsetup.product import getProductConfiguration
 from zope.app.container import contained
 from zope.app.component.interfaces import ISite
 from zope.app.publication.zopepublication import ZopePublication
@@ -36,6 +35,15 @@
 
 log = logging.getLogger('lovely.remotetask')
 
+try:
+    from Products import Five
+    from App.config import getConfiguration
+    ZOPE2 = True
+    del Five
+except ImportError:
+    from zope.app.appsetup.product import getProductConfiguration
+    ZOPE2 = False
+
 storage = threading.local()
 
 class TaskService(contained.Contained, persistent.Persistent):
@@ -46,7 +54,11 @@
     zope.interface.implements(interfaces.ITaskService)
 
     taskInterface = interfaces.ITask
-    processorFactory = processor.SimpleProcessor
+    if not ZOPE2:
+        processorFactory = processor.SimpleProcessor
+    else:
+        processorFactory = processor.SimpleZope2Processor
+        
     processorArguments = {'waitTime': 1.0}
 
     _scheduledJobs  = None
@@ -159,10 +171,13 @@
         if self._scheduledQueue == None:
             self._scheduledQueue = zc.queue.PersistentQueue()
         # Create the path to the service within the DB.
-        servicePath = [parent.__name__ for parent in zapi.getParents(self)
-                       if parent.__name__]
+        if not ZOPE2:
+            servicePath = [parent.__name__ for parent in zapi.getParents(self)
+                            if parent.__name__]
+            servicePath.append(self.__name__)
+        else:
+            servicePath = [path for path in self.getPhysicalPath() if path]
         servicePath.reverse()
-        servicePath.append(self.__name__)
         # Start the thread running the processor inside.
         processor = self.processorFactory(
             self._p_jar.db(), servicePath, **self.processorArguments)
@@ -196,11 +211,16 @@
         """Return name of the processing thread."""
         # This name isn't unique based on the path to self, but this doesn't
         # change the name that's been used in past versions.
-        path = [parent.__name__ for parent in zapi.getParents(self)
-                if parent.__name__]
-        path.append('remotetasks')
-        path.reverse()
-        path.append(self.__name__)
+        if not ZOPE2:
+            path = [parent.__name__ for parent in zapi.getParents(self)
+                    if parent.__name__]
+            path.append('remotetasks')
+            path.reverse()
+            path.append(self.__name__)
+        else:
+            path = [path for path in self.getPhysicalPath() if path]
+            path.append('remotetasks')
+            path.reverse()
         return '.'.join(path)
 
     def hasJobsWaiting(self, now=None):
@@ -334,13 +354,26 @@
     """get a list of services to start"""
 
     serviceNames = []
-    config = getProductConfiguration('lovely.remotetask')
-    if config is not None:
-        serviceNames = [name.strip()
-                        for name in config.get('autostart', '').split(',')]
+    # this does not work in Zope 2, because there is no "getProductConfiguration"
+    # Services has to be started in custom code 
+    if not ZOPE2:
+        config = getProductConfiguration('lovely.remotetask')
+        if config is not None:
+            serviceNames = [name.strip()
+                            for name in config.get('autostart', '').split(',')]
+    else:
+        config = getConfiguration().product_config
+        if config is not None:
+            task_config = config.get('lovely.remotetask', None)
+            if task_config:
+                autostart = task_config.get('autostart', '')
+                serviceNames = [name.strip()
+                                for name in autostart.split(',')]
+
     return serviceNames
 
 
+
 def bootStrapSubscriber(event):
     """Start the queue processing services based on the
        settings in zope.conf"""
@@ -404,3 +437,4 @@
         if (siteName == "*" or serviceName == "*") and serviceCount == 0:
             msg = 'no services started by directive %s'
             log.warn(msg % name)
+



More information about the Checkins mailing list