From b72a4f654b68c1047878ab92247b20a0a5253818 Mon Sep 17 00:00:00 2001 From: Wenjie Zheng <wenjie.zheng@tiolive.com> Date: Mon, 9 Mar 2015 23:34:00 +0000 Subject: [PATCH] Transition.py: Add WorkflowHistoryList class which contains maximum 16 workflow history. --- product/ERP5Workflow/Document/Transition.py | 130 ++++++++++++++++++-- 1 file changed, 120 insertions(+), 10 deletions(-) diff --git a/product/ERP5Workflow/Document/Transition.py b/product/ERP5Workflow/Document/Transition.py index 9b8f2ec3a5..542f8c0b98 100644 --- a/product/ERP5Workflow/Document/Transition.py +++ b/product/ERP5Workflow/Document/Transition.py @@ -27,15 +27,17 @@ ############################################################################## from AccessControl import ClassSecurityInfo - +from Acquisition import aq_base from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.Accessor.Base import _evaluateTales +from Products.ERP5Type.Globals import PersistentMapping from Products.DCWorkflow.Expression import StateChangeInfo from zLOG import LOG, ERROR, DEBUG, WARNING from Products.ERP5Type.Utils import convertToUpperCase, convertToMixedCase from Products.DCWorkflow.DCWorkflow import ObjectDeleted, ObjectMoved from copy import deepcopy +from Persistence import Persistent class Transition(XMLObject): """ @@ -119,15 +121,16 @@ class Transition(XMLObject): # Do not proceed in case of failure of before script if not before_script_success: - former_status = old_state # Remain in state - sci = StateChangeInfo( - document, workflow, former_status, self, old_sdef, new_sdef, kwargs) + former_status = old_state # Remain in state + self.setStatusOf(workflow.getId(), document, status_dict) + sci = StateChangeInfo( + document, workflow, former_status, self, old_sdef, new_sdef, kwargs) # put the error message in the workflow history - sci.setWorkflowVariable(error_message=before_script_error_message) - if validation_exc : - # reraise validation failed exception - raise validation_exc, None, validation_exc_traceback - return new_sdef + sci.setWorkflowVariable(error_message=before_script_error_message) + if validation_exc : + # reraise validation failed exception + raise validation_exc, None, validation_exc_traceback + return new_sdef # update state self._changeState(document) @@ -160,7 +163,8 @@ class Transition(XMLObject): for variable in self.contentValues(portal_type='Transition Variable'): status_dict[variable.getCausalityTitle()] = variable.getInitialValue(object=object) - workflow._updateWorkflowHistory(document, status_dict) + #workflow._updateWorkflowHistory(document, status_dict) + self.setStatusOf(workflow.getId(), document, status_dict) # Execute the "after" script. script_id = self.getAfterScriptId() if script_id is not None: @@ -205,3 +209,109 @@ class Transition(XMLObject): value = True #print "CALC", expr_value, '-->', value return value + + def setStatusOf(self, wf_id, ob, status): + """ Append an entry to the workflow history. + + o Invoked by transition execution. + """ + wfh = None + has_history = 0 + if getattr(aq_base(ob), 'workflow_history', None) is not None: + history = ob.workflow_history + if history is not None: + has_history = 1 + wfh = history.get(wf_id, None) + if wfh is not None and not isinstance(wfh, WorkflowHistoryList): + wfh = WorkflowHistoryList(list(wfh)) + ob.workflow_history[wf_id] = wfh + if wfh is None: + wfh = WorkflowHistoryList() + if not has_history: + ob.workflow_history = PersistentMapping() + ob.workflow_history[wf_id] = wfh + wfh.append(status) + +class WorkflowHistoryList(Persistent): + _bucket_size = 16 + + def __init__(self, iterable=None, prev=None): + self._prev = prev + self._slots = [] + if iterable is not None: + for x in iterable: + self.append(x) + + def __add__(self, iterable): + return self.__class__(tuple(self) + tuple(iterable)) + + def __contains__(self, item): + return item in tuple(self) + + def __eq__(self, other): + return tuple(self) == tuple(other) + + def __getitem__(self, index): + if index == -1: + return self._slots[-1] + elif isinstance(index, (int, long)): + if index < 0: + # XXX this implementation is not so good, but rarely used. + index += len(self) + iterator = self.__iter__() + for i in xrange(index): + iterator.next() + return iterator.next() + elif isinstance(index, slice): + return self.__class__((self[x] for x in + xrange(*index.indices(len(self))))) + else: + raise TypeError, 'tuple indices must be integers' + + def __getslice__(self, start, end): + return self.__getitem__(slice(start, end)) + + def __getstate__(self): + return (self._prev, self._slots) + + def __iter__(self): + bucket = self + stack = [] + while bucket is not None: + stack.append(bucket) + bucket = bucket._prev + for i in reversed(stack): + for j in i._slots: + yield j + + def __len__(self): + length = len(self._slots) + bucket = self._prev + while bucket is not None: + length += len(bucket._slots) + bucket = bucket._prev + return length + + def __mul__(self, x): + return self.__class__(tuple(self) * x) + + def __nonzero__(self): + return len(self._slots) != 0 or self._prev is not None + + def __repr__(self): + #return '%s' % repr(tuple(self.__iter__())) + return '<%s object at 0x%x %r>' % (self.__class__.__name__, id(self), tuple(self)) + + def __rmul__(self, x): + return self.__class__(x * tuple(self)) + + def __setstate__(self, state): + self._prev, self._slots = state + + def append(self, value): + if len(self._slots) < self._bucket_size: + self._slots.append(value) + self._p_changed = 1 + else: + self._prev = self.__class__(self._slots, prev=self._prev) + self._slots = [value] \ No newline at end of file -- 2.30.9