Commit a921a6b9 authored by Jean-Paul Smets's avatar Jean-Paul Smets

Implementation of ActiveProcess (an object intended to store the result of method calls)


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@124 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 055befcd
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
import ExtensionClass import ExtensionClass
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.CMFCore import CMFCorePermissions from Products.CMFCore import CMFCorePermissions
from Acquisition import aq_base
from zLOG import LOG from zLOG import LOG
...@@ -37,27 +38,17 @@ DEFAULT_ACTIVITY = 'SQLDict' ...@@ -37,27 +38,17 @@ DEFAULT_ACTIVITY = 'SQLDict'
#DEFAULT_ACTIVITY = 'RAMDict' #DEFAULT_ACTIVITY = 'RAMDict'
def flushActivity(object, invoke=0, **kw):
# flush all activities related to this object
try:
object.portal_activities.flush(self, invoke=invoke, **kw)
except:
# If the portal_activities were not created
# nothing to do
pass
class ActiveObject(ExtensionClass.Base): class ActiveObject(ExtensionClass.Base):
security = ClassSecurityInfo() security = ClassSecurityInfo()
def activate(self, activity=DEFAULT_ACTIVITY, **kw): def activate(self, activity=DEFAULT_ACTIVITY, active_process=None, **kw):
# activate returns an ActiveWrapper # activate returns an ActiveWrapper
# a queue can be provided as well as extra parameters # a queue can be provided as well as extra parameters
# which can be used for example to define deferred tasks # which can be used for example to define deferred tasks
try: try:
#if 1: #if 1:
return self.portal_activities.activate(self, activity, **kw) return self.portal_activities.activate(self, activity, active_process, **kw)
#else: #else:
except: except:
LOG("WARNING CMFActivity:",0, 'could not create activity for %s' % self.getRelativeUrl()) LOG("WARNING CMFActivity:",0, 'could not create activity for %s' % self.getRelativeUrl())
...@@ -65,6 +56,7 @@ class ActiveObject(ExtensionClass.Base): ...@@ -65,6 +56,7 @@ class ActiveObject(ExtensionClass.Base):
# return a passive object # return a passive object
return self return self
security.declareProtected( CMFCorePermissions.ModifyPortalContent, 'hasActivity' )
def flushActivity(self, invoke=0, **kw): def flushActivity(self, invoke=0, **kw):
# flush all activities related to this object # flush all activities related to this object
#try: #try:
...@@ -75,10 +67,14 @@ class ActiveObject(ExtensionClass.Base): ...@@ -75,10 +67,14 @@ class ActiveObject(ExtensionClass.Base):
# # nothing to do # # nothing to do
# pass # pass
def recursiveFlushActivity(self, **kw): security.declareProtected( CMFCorePermissions.ModifyPortalContent, 'hasActivity' )
def recursiveFlushActivity(self, invoke=0, **kw):
# flush all activities related to this object # flush all activities related to this object
# updateAll is defined in ERP5Type self.flushActivity(invoke=invoke, **kw)
self.recursiveApply(method=flushActivity, **kw) if hasattr(aq_base(self), 'objectValues'):
for o in self.objectValues():
if hasattr(aq_base(self), 'recursiveFlushActivity'):
o.recursiveFlushActivity(invoke=invoke, **kw)
security.declareProtected( CMFCorePermissions.View, 'hasActivity' ) security.declareProtected( CMFCorePermissions.View, 'hasActivity' )
def hasActivity(self, **kw): def hasActivity(self, **kw):
...@@ -91,3 +87,7 @@ class ActiveObject(ExtensionClass.Base): ...@@ -91,3 +87,7 @@ class ActiveObject(ExtensionClass.Base):
# If the portal_activities were not created # If the portal_activities were not created
# there can not be any activity # there can not be any activity
return 0 return 0
security.declareProtected( CMFCorePermissions.View, 'hasActivity' )
def getActiveProcess(self):
return self.portal_activities.getActiveProcess()
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
# Jean-Paul Smets-Solane <jp@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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.
#
##############################################################################
from Acquisition import aq_base
from Globals import InitializeClass, DTMLFile
from AccessControl import ClassSecurityInfo
from Products.CMFCore import CMFCorePermissions
from Products.ERP5Type.Base import Base
from Products.ERP5Type import PropertySheet
from zLOG import LOG
manage_addActiveProcessForm=DTMLFile('dtml/ActiveProcess_add', globals())
def addActiveProcess( self, id, title='', REQUEST=None ):
"""
Add a new Category and generate UID by calling the
ZSQLCatalog
"""
sf = ActiveProcess( id )
sf._setTitle(title)
self._setObject( id, sf )
sf = self._getOb( id )
sf.reindexObject()
if REQUEST is not None:
return self.manage_main(self, REQUEST, update_menu=1)
class ActiveProcess(Base):
"""
ActiveProcess is used to centralise interaction between multiple ActiveObject
"""
meta_type='CMF Active Process'
portal_type=None # may be useful in the future...
isPortalContent = 0
isRADContent = 1
icon = None
# Declarative security
security = ClassSecurityInfo()
security.declareProtected(CMFCorePermissions.ManagePortal,
'manage_editProperties',
'manage_changeProperties',
'manage_propertiesForm',
)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.SimpleItem )
# Declarative constructors
constructors = (manage_addActiveProcessForm, addActiveProcess)
# Base methods
security.declareProtected(CMFCorePermissions.ManagePortal, 'postError')
def postError(self, error):
if not hasattr(aq_base(self), 'error_list'):
self.error_list = []
self.error_list.append(error)
security.declareProtected(CMFCorePermissions.ManagePortal, 'getErrorList')
def getErrorList(self):
"""
Returns the list of errors
"""
return self.error_list
security.declareProtected(CMFCorePermissions.ManagePortal, 'getErrorListText')
def getErrorListText(self):
"""
Returns the list of errors as text
"""
return '\n'.join(self.error_list)
security.declareProtected(CMFCorePermissions.ManagePortal, 'activateResult')
def activateResult(self, result):
if result not in (None, 0, '', (), []):
self.activate().postError(result)
InitializeClass( ActiveProcess )
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
############################################################################## ##############################################################################
import pickle import pickle
from Acquisition import aq_base
from Products.CMFActivity.ActivityTool import Message from Products.CMFActivity.ActivityTool import Message
from zLOG import LOG from zLOG import LOG
......
...@@ -27,10 +27,10 @@ ...@@ -27,10 +27,10 @@
############################################################################## ##############################################################################
from Products.CMFCore import CMFCorePermissions from Products.CMFCore import CMFCorePermissions
from Products.CMFCore.PortalFolder import PortalFolder from Products.ERP5Type.Document.Folder import Folder
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.CMFCore.utils import UniqueObject, _checkPermission, _getAuthenticatedUser from Products.CMFCore.utils import UniqueObject, _checkPermission, _getAuthenticatedUser
from Globals import InitializeClass, DTMLFile from Globals import InitializeClass, DTMLFile, get_request
from Acquisition import aq_base from Acquisition import aq_base
from DateTime.DateTime import DateTime from DateTime.DateTime import DateTime
import threading import threading
...@@ -56,11 +56,17 @@ def registerActivity(activity): ...@@ -56,11 +56,17 @@ def registerActivity(activity):
activity_dict[activity.__name__] = activity_instance activity_dict[activity.__name__] = activity_instance
class Message: class Message:
def __init__(self, object, activity_kw, method_id, args, kw): def __init__(self, object, active_process, activity_kw, method_id, args, kw):
if type(object) is type('a'): if type(object) is type('a'):
self.object_path = object.split('/') self.object_path = object.split('/')
else: else:
self.object_path = object.getPhysicalPath() self.object_path = object.getPhysicalPath()
if type(active_process) is type('a'):
self.active_process = active_process.split('/')
elif active_process is None:
self.active_process = None
else:
self.active_process = active_process.getPhysicalPath()
self.activity_kw = activity_kw self.activity_kw = activity_kw
self.method_id = method_id self.method_id = method_id
self.args = args self.args = args
...@@ -73,7 +79,12 @@ class Message: ...@@ -73,7 +79,12 @@ class Message:
LOG('WARNING ActivityTool', 0, LOG('WARNING ActivityTool', 0,
'Trying to call method %s on object %s' % (self.method_id, self.object_path)) 'Trying to call method %s on object %s' % (self.method_id, self.object_path))
object = activity_tool.unrestrictedTraverse(self.object_path) object = activity_tool.unrestrictedTraverse(self.object_path)
getattr(object, self.method_id)(*self.args, **self.kw) REQUEST = get_request()
REQUEST.active_process = self.active_process
result = getattr(object, self.method_id)(*self.args, **self.kw)
if REQUEST.active_process is not None:
active_process = activity_tool.getActiveProcess()
active_process.activateResult(result) # XXX Allow other method_id in future
self.__is_executed = 1 self.__is_executed = 1
except: except:
LOG('WARNING ActivityTool', 0, LOG('WARNING ActivityTool', 0,
...@@ -85,49 +96,69 @@ class Message: ...@@ -85,49 +96,69 @@ class Message:
class Method: class Method:
def __init__(self, passive_self, activity, kw, method_id): def __init__(self, passive_self, activity, active_process, kw, method_id):
self.__passive_self = passive_self self.__passive_self = passive_self
self.__activity = activity self.__activity = activity
self.__active_process = active_process
self.__kw = kw self.__kw = kw
self.__method_id = method_id self.__method_id = method_id
def __call__(self, *args, **kw): def __call__(self, *args, **kw):
m = Message(self.__passive_self, self.__kw, self.__method_id, args, kw) m = Message(self.__passive_self, self.__active_process, self.__kw, self.__method_id, args, kw)
activity_dict[self.__activity].queueMessage(self.__passive_self.portal_activities, m) activity_dict[self.__activity].queueMessage(self.__passive_self.portal_activities, m)
class ActiveWrapper: class ActiveWrapper:
def __init__(self, passive_self, activity, **kw): def __init__(self, passive_self, activity, active_process, **kw):
self.__dict__['__passive_self'] = passive_self self.__dict__['__passive_self'] = passive_self
self.__dict__['__activity'] = activity self.__dict__['__activity'] = activity
self.__dict__['__active_process'] = active_process
self.__dict__['__kw'] = kw self.__dict__['__kw'] = kw
def __getattr__(self, id): def __getattr__(self, id):
return Method(self.__dict__['__passive_self'], self.__dict__['__activity'], return Method(self.__dict__['__passive_self'], self.__dict__['__activity'],
self.__dict__['__active_process'],
self.__dict__['__kw'], id) self.__dict__['__kw'], id)
class ActivityTool (UniqueObject, PortalFolder): class ActivityTool (Folder, UniqueObject):
""" """
This is a ZSQLCatalog that filters catalog queries. This is a ZSQLCatalog that filters catalog queries.
It is based on ZSQLCatalog It is based on ZSQLCatalog
""" """
id = 'portal_activities' id = 'portal_activities'
meta_type = 'CMF Activity Tool' meta_type = 'CMF Activity Tool'
allowed_types = ( 'CMF Active Process', )
security = ClassSecurityInfo() security = ClassSecurityInfo()
tic_lock = threading.Lock() tic_lock = threading.Lock()
manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } manage_options = tuple(
[ { 'label' : 'Overview', 'action' : 'manage_overview' }
, { 'label' : 'Activities', 'action' : 'manageActivities' } , { 'label' : 'Activities', 'action' : 'manageActivities' }
, ,
) ] + list(Folder.manage_options))
security.declareProtected( CMFCorePermissions.ManagePortal , 'manageActivities' ) security.declareProtected( CMFCorePermissions.ManagePortal , 'manageActivities' )
manageActivities = DTMLFile( 'dtml/manageActivities', globals() ) manageActivities = DTMLFile( 'dtml/manageActivities', globals() )
security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' )
manage_overview = DTMLFile( 'dtml/explainActivityTool', globals() )
def __init__(self):
return Folder.__init__(self, ActivityTool.id)
# Filter content (ZMI))
def filtered_meta_types(self, user=None):
# Filters the list of available meta types.
all = ActivityTool.inheritedAttribute('filtered_meta_types')(self)
meta_types = []
for meta_type in self.all_meta_types():
if meta_type['name'] in self.allowed_types:
meta_types.append(meta_type)
return meta_types
def initialize(self): def initialize(self):
global is_initialized global is_initialized
from Activity import RAMQueue, RAMDict, SQLDict, ZODBDict from Activity import RAMQueue, RAMDict, SQLDict
# Initialize each queue # Initialize each queue
for activity in activity_list: for activity in activity_list:
activity.initialize(self) activity.initialize(self)
...@@ -187,10 +218,10 @@ class ActivityTool (UniqueObject, PortalFolder): ...@@ -187,10 +218,10 @@ class ActivityTool (UniqueObject, PortalFolder):
return 1 return 1
return 0 return 0
def activate(self, object, activity, **kw): def activate(self, object, activity, active_process, **kw):
global is_initialized global is_initialized
if not is_initialized: self.initialize() if not is_initialized: self.initialize()
return ActiveWrapper(object, activity, **kw) return ActiveWrapper(object, activity, active_process, **kw)
def flush(self, object, invoke=0, **kw): def flush(self, object, invoke=0, **kw):
global is_initialized global is_initialized
...@@ -203,10 +234,11 @@ class ActivityTool (UniqueObject, PortalFolder): ...@@ -203,10 +234,11 @@ class ActivityTool (UniqueObject, PortalFolder):
def invoke(self, message): def invoke(self, message):
message(self) message(self)
def newMessage(self, activity, path, activity_kw, method_id, *args, **kw): def newMessage(self, activity, path, active_process, activity_kw, method_id, *args, **kw):
# Some Security Cheking should be made here XXX
global is_initialized global is_initialized
if not is_initialized: self.initialize() if not is_initialized: self.initialize()
activity_dict[activity].queueMessage(self, Message(path, activity_kw, method_id, args, kw)) activity_dict[activity].queueMessage(self, Message(path, active_process, activity_kw, method_id, args, kw))
def manageInvoke(self, object_path, method_id, REQUEST=None): def manageInvoke(self, object_path, method_id, REQUEST=None):
""" """
...@@ -240,4 +272,21 @@ class ActivityTool (UniqueObject, PortalFolder): ...@@ -240,4 +272,21 @@ class ActivityTool (UniqueObject, PortalFolder):
message_list += activity.getMessageList(self) message_list += activity.getMessageList(self)
return message_list return message_list
security.declareProtected( CMFCorePermissions.ManagePortal , 'newActiveProcess' )
def newActiveProcess(self):
from ActiveProcess import addActiveProcess
new_id = str(self.generateNewId())
addActiveProcess(self, new_id)
return self._getOb(new_id)
def reindexObject(self):
self.immediateReindexObject()
def getActiveProcess(self):
REQUEST = get_request()
if REQUEST.active_process:
return self.unrestrictedTraverse(REQUEST.active_process)
return None
InitializeClass(ActivityTool) InitializeClass(ActivityTool)
...@@ -42,8 +42,8 @@ document_classes = generateInitFiles(this_module, globals()) ...@@ -42,8 +42,8 @@ document_classes = generateInitFiles(this_module, globals())
from Products.ERP5Type.Utils import initializeProduct, updateGlobals from Products.ERP5Type.Utils import initializeProduct, updateGlobals
# Define object classes and tools # Define object classes and tools
import ActivityTool import ActivityTool, ActiveProcess
object_classes = () object_classes = (ActiveProcess.ActiveProcess, )
portal_tools = (ActivityTool.ActivityTool,) portal_tools = (ActivityTool.ActivityTool,)
content_classes = () content_classes = ()
content_constructors = () content_constructors = ()
......
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Category',
help_product='ERP5',
help_topic='Category_Add.stx'
)">
<p class="form-help">
A Folder contains other objects. Use Folders to organize your
web objects in to logical groups. The <em>create public interface</em>
option creates an index document inside the Folder to give the
Folder a default HTML representation. The <em>create user folder</em>
option creates a User Folder inside the Folder to hold authorization
information for the Folder.
</p>
<FORM ACTION="addActiveProcess" METHOD="POST">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40" />
</td>
</tr>
<dtml-if
"_.SecurityCheckPermission('Add Documents, Images, and Files',this())">
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="createPublic:int" value="1"
id="cbCreatePublic">
<label for="cbCreatePublic">Create public interface</label>
</div>
</td>
</tr>
</dtml-if>
<dtml-if
"_.SecurityCheckPermission('Add User Folders',this())">
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="createUserF:int" value="1"
id="cbCreateUserF">
<label for="cbCreateUserF">Create user folder</label>
</div>
</td>
</tr>
</dtml-if>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value="Add" />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<p>Explain CategoryTool</p>
<dtml-var manage_page_footer>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment