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 @@
import ExtensionClass
from AccessControl import ClassSecurityInfo
from Products.CMFCore import CMFCorePermissions
from Acquisition import aq_base
from zLOG import LOG
......@@ -37,27 +38,17 @@ DEFAULT_ACTIVITY = 'SQLDict'
#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):
security = ClassSecurityInfo()
def activate(self, activity=DEFAULT_ACTIVITY, **kw):
def activate(self, activity=DEFAULT_ACTIVITY, active_process=None, **kw):
# activate returns an ActiveWrapper
# a queue can be provided as well as extra parameters
# which can be used for example to define deferred tasks
try:
#if 1:
return self.portal_activities.activate(self, activity, **kw)
return self.portal_activities.activate(self, activity, active_process, **kw)
#else:
except:
LOG("WARNING CMFActivity:",0, 'could not create activity for %s' % self.getRelativeUrl())
......@@ -65,6 +56,7 @@ class ActiveObject(ExtensionClass.Base):
# return a passive object
return self
security.declareProtected( CMFCorePermissions.ModifyPortalContent, 'hasActivity' )
def flushActivity(self, invoke=0, **kw):
# flush all activities related to this object
#try:
......@@ -75,10 +67,14 @@ class ActiveObject(ExtensionClass.Base):
# # nothing to do
# pass
def recursiveFlushActivity(self, **kw):
security.declareProtected( CMFCorePermissions.ModifyPortalContent, 'hasActivity' )
def recursiveFlushActivity(self, invoke=0, **kw):
# flush all activities related to this object
# updateAll is defined in ERP5Type
self.recursiveApply(method=flushActivity, **kw)
self.flushActivity(invoke=invoke, **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' )
def hasActivity(self, **kw):
......@@ -91,3 +87,7 @@ class ActiveObject(ExtensionClass.Base):
# If the portal_activities were not created
# there can not be any activity
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 @@
##############################################################################
import pickle
from Acquisition import aq_base
from Products.CMFActivity.ActivityTool import Message
from zLOG import LOG
......
......@@ -27,10 +27,10 @@
##############################################################################
from Products.CMFCore import CMFCorePermissions
from Products.CMFCore.PortalFolder import PortalFolder
from Products.ERP5Type.Document.Folder import Folder
from AccessControl import ClassSecurityInfo
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 DateTime.DateTime import DateTime
import threading
......@@ -56,11 +56,17 @@ def registerActivity(activity):
activity_dict[activity.__name__] = activity_instance
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'):
self.object_path = object.split('/')
else:
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.method_id = method_id
self.args = args
......@@ -73,7 +79,12 @@ class Message:
LOG('WARNING ActivityTool', 0,
'Trying to call method %s on object %s' % (self.method_id, 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
except:
LOG('WARNING ActivityTool', 0,
......@@ -85,49 +96,69 @@ class Message:
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.__activity = activity
self.__active_process = active_process
self.__kw = kw
self.__method_id = method_id
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)
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__['__activity'] = activity
self.__dict__['__active_process'] = active_process
self.__dict__['__kw'] = kw
def __getattr__(self, id):
return Method(self.__dict__['__passive_self'], self.__dict__['__activity'],
self.__dict__['__active_process'],
self.__dict__['__kw'], id)
class ActivityTool (UniqueObject, PortalFolder):
class ActivityTool (Folder, UniqueObject):
"""
This is a ZSQLCatalog that filters catalog queries.
It is based on ZSQLCatalog
"""
id = 'portal_activities'
meta_type = 'CMF Activity Tool'
allowed_types = ( 'CMF Active Process', )
security = ClassSecurityInfo()
tic_lock = threading.Lock()
manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
manage_options = tuple(
[ { 'label' : 'Overview', 'action' : 'manage_overview' }
, { 'label' : 'Activities', 'action' : 'manageActivities' }
,
)
] + list(Folder.manage_options))
security.declareProtected( CMFCorePermissions.ManagePortal , 'manageActivities' )
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):
global is_initialized
from Activity import RAMQueue, RAMDict, SQLDict, ZODBDict
from Activity import RAMQueue, RAMDict, SQLDict
# Initialize each queue
for activity in activity_list:
activity.initialize(self)
......@@ -187,10 +218,10 @@ class ActivityTool (UniqueObject, PortalFolder):
return 1
return 0
def activate(self, object, activity, **kw):
def activate(self, object, activity, active_process, **kw):
global is_initialized
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):
global is_initialized
......@@ -203,10 +234,11 @@ class ActivityTool (UniqueObject, PortalFolder):
def invoke(self, message):
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
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):
"""
......@@ -240,4 +272,21 @@ class ActivityTool (UniqueObject, PortalFolder):
message_list += activity.getMessageList(self)
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)
......@@ -42,8 +42,8 @@ document_classes = generateInitFiles(this_module, globals())
from Products.ERP5Type.Utils import initializeProduct, updateGlobals
# Define object classes and tools
import ActivityTool
object_classes = ()
import ActivityTool, ActiveProcess
object_classes = (ActiveProcess.ActiveProcess, )
portal_tools = (ActivityTool.ActivityTool,)
content_classes = ()
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