Commit 797a8c29 authored by Yoshinori Okuji's avatar Yoshinori Okuji

Support grouping active objects.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@3790 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent d72a36fb
This diff is collapsed.
......@@ -42,6 +42,7 @@ from AccessControl.SecurityManagement import newSecurityManager
import threading
import sys
from ZODB.POSException import ConflictError
from OFS.Traversable import NotFound
from zLOG import LOG
......@@ -86,34 +87,57 @@ class Message:
self.user_name = str(_getAuthenticatedUser(self))
# Store REQUEST Info ?
def getObject(self, activity_tool):
return activity_tool.unrestrictedTraverse(self.object_path)
def getObjectList(self, activity_tool):
try:
expand_method_id = self.activity_kw['expand_method_id']
except KeyError:
return [self.getObject()]
obj = self.getObject(activity_tool)
# FIXME: how to pass parameters?
return getattr(obj, expand_method_id)()
def hasExpandMethod(self):
return self.activity_kw.has_key('expand_method_id')
def changeUser(self, user_name, activity_tool):
uf = activity_tool.getPortalObject().acl_users
user = uf.getUserById(user_name)
if user is not None:
user = user.__of__(uf)
newSecurityManager(None, user)
return user
def activateResult(self, activity_tool, result, object):
if self.active_process is not None:
active_process = activity_tool.unrestrictedTraverse(self.active_process)
if isinstance(result,Error):
result.edit(object_path=object)
result.edit(method_id=self.method_id)
active_process.activateResult(result) # XXX Allow other method_id in future
else:
active_process.activateResult(Error(object_path=object,method_id=self.method_id,result=result)) # XXX Allow other method_id in future
def __call__(self, activity_tool):
try:
# 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)
object = self.getObject(activity_tool)
# Change user if required (TO BE DONE)
activity_tool._v_active_process = self.active_process # Store the active_process as volatile thread variable
# We will change the user only in order to execute this method
current_user = str(_getAuthenticatedUser(self))
uf = object.getPortalObject().acl_users
user = uf.getUserById(self.user_name)
if user is not None:
user = user.__of__(uf)
newSecurityManager(None, user)
user = self.changeUser(self.user_name, activity_tool)
result = getattr(object, self.method_id)(*self.args, **self.kw)
# Use again the previous user
if user is not None:
user = uf.getUserById(current_user).__of__(uf)
newSecurityManager(None, user)
if activity_tool._v_active_process is not None:
active_process = activity_tool.getActiveProcess()
if isinstance(result,Error):
result.edit(object_path=object)
result.edit(method_id=self.method_id)
active_process.activateResult(result) # XXX Allow other method_id in future
else:
active_process.activateResult(Error(object_path=object,method_id=self.method_id,result=result)) # XXX Allow other method_id in future
self.changeUser(current_user, activity_tool)
self.activateResult(activity_tool, result, object)
self.is_executed = 1
except ConflictError:
raise
except:
self.is_executed = 0
LOG('WARNING ActivityTool', 0,
......@@ -236,6 +260,8 @@ class ActivityTool (Folder, UniqueObject):
for activity in activity_list:
try:
activity.distribute(self, node_count)
except ConflictError:
raise
except:
LOG('CMFActivity:', 100, 'Core call to distribute failed for activity %s' % activity, error=sys.exc_info())
......@@ -280,6 +306,7 @@ class ActivityTool (Folder, UniqueObject):
try:
activity.tic(self, processing_node) # Transaction processing is the responsability of the activity
has_awake_activity = has_awake_activity or activity.isAwake(self, processing_node)
#LOG('ActivityTool tic', 0, 'has_awake_activity = %r, activity = %r, activity.isAwake(self, processing_node) = %r' % (has_awake_activity, activity, activity.isAwake(self, processing_node)))
except ConflictError:
raise
except:
......@@ -356,7 +383,65 @@ class ActivityTool (Folder, UniqueObject):
def invoke(self, message):
message(self)
def invokeGroup(self, method_id, message_list):
# Invoke a group method.
object_list = []
expanded_object_list = []
new_message_list = []
path_dict = {}
# Filter the list of messages. If an object is not available, ignore such a message.
# In addition, expand an object if necessary, and make sure that no duplication happens.
for m in message_list:
try:
obj = m.getObject(self)
object_list.append(obj)
if m.hasExpandMethod():
for obj in m.getObjectList(self):
path = obj.getPath()
if path not in path_dict:
path_dict[path] = None
expanded_object_list.append(obj)
else:
path = obj.getPath()
if path not in path_dict:
path_dict[path] = None
expanded_object_list.append(obj)
new_message_list.append(m)
except ConflictError:
raise
except:
m.is_executed = 0
LOG('WARNING ActivityTool', 0,
'Could not call method %s on object %s' % (m.method_id, m.object_path), error=sys.exc_info())
if len(expanded_object_list) > 0:
try:
method = self.unrestrictedTraverse(method_id)
# FIXME: how to pass parameters?
# FIXME: how to apply security here?
result = method(expanded_object_list)
except ConflictError:
raise
except:
for m in new_message_list:
m.is_executed = 0
LOG('WARNING ActivityTool', 0,
'Could not call method %s on objects %s' % (method_id, expanded_object_list), error=sys.exc_info())
else:
for i in xrange(len(object_list)):
object = object_list[i]
m = new_message_list[i]
try:
m.activateResult(self, result, object)
m.is_executed = 1
except ConflictError:
raise
except:
m.is_executed = 0
LOG('WARNING ActivityTool', 0,
'Could not call method %s on object %s' % (m.method_id, m.object_path), error=sys.exc_info())
def newMessage(self, activity, path, active_process, activity_kw, method_id, *args, **kw):
# Some Security Cheking should be made here XXX
global is_initialized
......@@ -412,12 +497,6 @@ class ActivityTool (Folder, UniqueObject):
def reindexObject(self):
self.immediateReindexObject()
def getActiveProcess(self):
active_process = getattr(self, '_v_active_process')
if active_process:
return self.unrestrictedTraverse(active_process)
return None
# Active synchronisation methods
def validateOrder(self, message, validator_id, validation_value):
global is_initialized
......
......@@ -9,15 +9,16 @@ class_file:
</dtml-comment>
<params></params>
CREATE TABLE `message` (
`uid` int(11) NOT NULL auto_increment,
`uid` INT UNSIGNED NOT NULL auto_increment,
`date` datetime,
`path` VARCHAR(255),
`method_id` VARCHAR(40),
`method_id` VARCHAR(255),
`processing_node` INT DEFAULT -1,
`processing` INT DEFAULT 0,
`processing` TINYINT DEFAULT 0,
`processing_date` datetime,
`priority` INT DEFAULT 0,
`broadcast` INT DEFAULT 0,
`priority` TINYINT DEFAULT 0,
`broadcast` TINYINT DEFAULT 0,
`group_method_id` VARCHAR(255) DEFAULT '',
`message` BLOB,
PRIMARY KEY (`uid`),
KEY `date` (`date`),
......
<dtml-comment>
title:
connection_id:cmf_activity_sql_connection
max_rows:1
max_rows:0
max_cache:0
cache_time:0
class_name:
......@@ -10,14 +10,23 @@ class_file:
<params>processing_node
priority
to_date
to_processing_date</params>
SELECT * FROM
to_processing_date
group_method_id</params>
SELECT DISTINCT * FROM
message
WHERE
processing <> 1
<dtml-if processing_node> AND processing_node = <dtml-sqlvar processing_node type="int"> </dtml-if>
<dtml-if priority> AND priority = <dtml-sqlvar priority type="int"> </dtml-if>
<dtml-if to_date>AND date <= <dtml-sqlvar to_date type="datetime"> </dtml-if>
<dtml-if group_method_id>AND group_method_id = <dtml-sqlvar group_method_id type="string"> </dtml-if>
GROUP BY
path, method_id
ORDER BY
priority, date
<dtml-if group_method_id>
LIMIT 100
<dtml-else>
LIMIT 1
</dtml-if>
......@@ -13,7 +13,8 @@ message
priority
broadcast
date
processing_node=-1</params>
processing_node=-1
group_method_id</params>
INSERT INTO message
SET
path = <dtml-sqlvar path type="string">,
......@@ -23,4 +24,5 @@ SET
processing = -1,
priority = <dtml-sqlvar priority type="int">,
broadcast = <dtml-sqlvar broadcast type="int">,
group_method_id = <dtml-sqlvar group_method_id type="string">,
message = <dtml-sqlvar message type="string">
......@@ -13,20 +13,22 @@ message_list
priority_list
broadcast_list
date_list
processing_node_list</params>
processing_node_list
group_method_id_list</params>
INSERT INTO message
(path, date, method_id, processing_node, processing, priority, broadcast, message)
(path, date, method_id, processing_node, processing, priority, broadcast, group_method_id, message)
VALUES
<dtml-in prefix="loop" expr="_.range(_.len(path_list))">
<dtml-if sequence-start><dtml-else>,</dtml-if>
(
<dtml-sqlvar expr="path_list[loop_item]" type="string">,
<dtml-if date_list><dtml-sqlvar expr="date_list[loop_item]" type="string"><dtml-else><dtml-sqlvar "_.DateTime()" type="datetime"></dtml-if>,
<dtml-if date_list><dtml-sqlvar expr="date_list[loop_item]" type="datetime"><dtml-else><dtml-sqlvar "_.DateTime()" type="datetime"></dtml-if>,
<dtml-sqlvar expr="method_id_list[loop_item]" type="string">,
<dtml-if processing_node_list><dtml-sqlvar expr="processing_node_list[loop_item]" type="int"><dtml-else>-1</dtml-if>,
-1,
<dtml-sqlvar expr="priority_list[loop_item]" type="int">,
<dtml-sqlvar expr="broadcast_list[loop_item]" type="int">,
<dtml-sqlvar expr="group_method_id_list[loop_item]" type="string">,
<dtml-sqlvar expr="message_list[loop_item]" type="string">
)
</dtml-in>
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