Commit 603c8600 authored by wenjie.zheng's avatar wenjie.zheng

ERP5Workflow Method Generation for live test.

parent 425949fe
...@@ -165,100 +165,135 @@ class WorkflowMethod(Method): ...@@ -165,100 +165,135 @@ class WorkflowMethod(Method):
# already better than what we had. I (JPS) would prefer to use # already better than what we had. I (JPS) would prefer to use
# critical sections in this part of the code and a # critical sections in this part of the code and a
# thread variable which tells in which semantic context the code # thread variable which tells in which semantic context the code
# should ne executed. - XXX # should be executed. - XXX
return self._m(instance, *args, **kw) return self._m(instance, *args, **kw)
#=============== Workflow5 Project, Wenjie, Dec 2014 =====================
# Get Workflow5 which is an ERP5 default module.
# Available workflow5 bt should be initially installed.
# Only check Base Type obejct:
wf5_module = instance.getPortalObject().getDefaultModule(portal_type="Workflow")
valid_list5 = []
valid_transition_item_list5 = []
#if instance.portal_type == "Object Type":
#raise NotImplementedError (instance.getTypeInfo())# Base Type at Object Type
if hasattr(instance.getTypeInfo(),"workflow_list"):
WorkflowList = instance.getTypeInfo().getTypeWorkflowList()
#raise NotImplementedError (WorkflowList)# new_workflow
for wf_id in WorkflowList:
wf5 = wf5_module._getOb(wf_id)
for transition in wf5.objectValues(portal_type='Transition'):
valid_list5.append(transition.getId())
#raise NotImplementedError (valid_list5) # ['transition1', 'transition2']
if valid_list5:
valid_transition_item_list5.append((wf_id, valid_list5))
# execute method
for wf_id, transition_list in valid_transition_item_list5:
# ??? see original <245, 256>
for tr in transition_list:
method5 = wf5_module._getOb(wf_id)._getOb(tr)
method5.execute(instance) # also execute before & after script
#return method5._changeState(instance) # only change state
#raise NotImplementedError (instance.getId()) # new_object
#raise NotImplementedError (method5) # Transition at transition1
#raise NotImplementedError (instance.getCategoryStateTitle()) # None
#=================================== wf5 =================================
# New implementation does not use any longer wrapWorkflowMethod # New implementation does not use any longer wrapWorkflowMethod
# but directly calls the workflow methods # but directly calls the workflow methods
try: try:
wf = getattr(instance.getPortalObject(), 'portal_workflow') wf = getattr(instance.getPortalObject(), 'portal_workflow') # portal_workflow is a list!
except AttributeError: except AttributeError:
# XXX instance is unwrapped(no acquisition) # XXX instance is unwrapped(no acquisition)
# XXX I must think that what is a correct behavior.(Yusei) # XXX I must think that what is a correct behavior.(Yusei)
return self._m(instance, *args, **kw) return self._m(instance, *args, **kw)
try:
# Build a list of transitions which may need to be invoked # Build a list of transitions which may need to be invoked
instance_path = instance.getPhysicalPath() instance_path = instance.getPhysicalPath()
portal_type = instance.portal_type portal_type = instance.portal_type
transactional_variable = getTransactionalVariable() transactional_variable = getTransactionalVariable()
invoke_once_dict = self._invoke_once.get(portal_type, {}) invoke_once_dict = self._invoke_once.get(portal_type, {})
valid_invoke_once_item_list = [] valid_invoke_once_item_list = []
# Only keep those transitions which were never invoked # Only keep those transitions which were never invoked
once_transition_dict = {} once_transition_dict = {}
for wf_id, transition_list in invoke_once_dict.iteritems(): for wf_id, transition_list in invoke_once_dict.iteritems():
valid_transition_list = [] valid_transition_list = []
for transition_id in transition_list: for transition_id in transition_list:
once_transition_key = ('Products.ERP5Type.Base.WorkflowMethod.__call__', once_transition_key = ('Products.ERP5Type.Base.WorkflowMethod.__call__',
wf_id, transition_id, instance_path) wf_id, transition_id, instance_path)
once_transition_dict[(wf_id, transition_id)] = once_transition_key once_transition_dict[(wf_id, transition_id)] = once_transition_key
if once_transition_key not in transactional_variable: if once_transition_key not in transactional_variable:
valid_transition_list.append(transition_id) valid_transition_list.append(transition_id)
if valid_transition_list: if valid_transition_list:
valid_invoke_once_item_list.append((wf_id, valid_transition_list)) valid_invoke_once_item_list.append((wf_id, valid_transition_list))
candidate_transition_item_list = valid_invoke_once_item_list + \ candidate_transition_item_list = valid_invoke_once_item_list + \
self._invoke_always.get(portal_type, {}).items() self._invoke_always.get(portal_type, {}).items()
#LOG('candidate_transition_item_list %s' % self.__name__, 0, str(candidate_transition_item_list)) #LOG('candidate_transition_item_list %s' % self.__name__, 0, str(candidate_transition_item_list))
# Try to return immediately if there are no transition to invoke # Try to return immediately if there are no transition to invoke
if not candidate_transition_item_list: if not candidate_transition_item_list:
return apply(self.__dict__['_m'], (instance,) + args, kw) return apply(self.__dict__['_m'], (instance,) + args, kw)
# Prepare a list of transitions which should be invoked. # Prepare a list of transitions which should be invoked.
# This list is based on the results of isWorkflowMethodSupported. # This list is based on the results of isWorkflowMethodSupported.
# An interaction is ignored if the guard prevents execution. # An interaction is ignored if the guard prevents execution.
# Otherwise, an exception is raised if the workflow transition does not # Otherwise, an exception is raised if the workflow transition does not
# exist from the current state, or if the guard rejects it. # exist from the current state, or if the guard rejects it.
valid_transition_item_list = [] valid_transition_item_list = []
for wf_id, transition_list in candidate_transition_item_list: for wf_id, transition_list in candidate_transition_item_list:
candidate_workflow = wf[wf_id] candidate_workflow = wf[wf_id]
valid_list = [] valid_list = []
for transition_id in transition_list: for transition_id in transition_list:
if candidate_workflow.isWorkflowMethodSupported(instance, transition_id): if candidate_workflow.isWorkflowMethodSupported(instance, transition_id):
valid_list.append(transition_id) valid_list.append(transition_id)
once_transition_key = once_transition_dict.get((wf_id, transition_id)) once_transition_key = once_transition_dict.get((wf_id, transition_id))
if once_transition_key: if once_transition_key:
# a run-once transition, prevent it from running again in # a run-once transition, prevent it from running again in
# the same transaction # the same transaction
transactional_variable[once_transition_key] = 1 transactional_variable[once_transition_key] = 1
elif candidate_workflow.__class__.__name__ == 'DCWorkflowDefinition': elif candidate_workflow.__class__.__name__ == 'DCWorkflowDefinition':
raise UnsupportedWorkflowMethod(instance, wf_id, transition_id) raise UnsupportedWorkflowMethod(instance, wf_id, transition_id)
# XXX Keep the log for projects that needs to comment out # XXX Keep the log for projects that needs to comment out
# the previous line. # the previous line.
LOG("WorkflowMethod.__call__", ERROR, LOG("WorkflowMethod.__call__", ERROR,
"Transition %s/%s on %r is ignored. Current state is %r." "Transition %s/%s on %r is ignored. Current state is %r."
% (wf_id, transition_id, instance, % (wf_id, transition_id, instance,
candidate_workflow._getWorkflowStateOf(instance, id_only=1))) candidate_workflow._getWorkflowStateOf(instance, id_only=1)))
if valid_list: if valid_list:
valid_transition_item_list.append((wf_id, valid_list)) valid_transition_item_list.append((wf_id, valid_list))
#LOG('valid_transition_item_list %s' % self.__name__, 0, str(valid_transition_item_list)) #LOG('valid_transition_item_list %s' % self.__name__, 0, str(valid_transition_item_list))
# Call whatever must be called before changing states # Call whatever must be called before changing states
for wf_id, transition_list in valid_transition_item_list: for wf_id, transition_list in valid_transition_item_list:
wf[wf_id].notifyBefore(instance, transition_list, args=args, kw=kw) wf[wf_id].notifyBefore(instance, transition_list, args=args, kw=kw)
# Compute expected result # Compute expected result
result = apply(self.__dict__['_m'], (instance,) + args, kw) result = apply(self.__dict__['_m'], (instance,) + args, kw)
# Change the state of statefull workflows # Change the state of statefull workflows
for wf_id, transition_list in valid_transition_item_list: for wf_id, transition_list in valid_transition_item_list:
try: try:
wf[wf_id].notifyWorkflowMethod(instance, transition_list, args=args, kw=kw) wf[wf_id].notifyWorkflowMethod(instance, transition_list, args=args, kw=kw)
except ObjectDeleted: except ObjectDeleted:
# Re-raise with a different result. # Re-raise with a different result.
raise ObjectDeleted(result) raise ObjectDeleted(result)
except ObjectMoved, ex: except ObjectMoved, ex:
# Re-raise with a different result. # Re-raise with a different result.
raise ObjectMoved(ex.getNewObject(), result) raise ObjectMoved(ex.getNewObject(), result)
# Call whatever must be called after changing states # Call whatever must be called after changing states
for wf_id, transition_list in valid_transition_item_list: for wf_id, transition_list in valid_transition_item_list:
wf[wf_id].notifySuccess(instance, transition_list, result, args=args, kw=kw) # /product/ERP5/InteractionWorkflow.py, update value, provide info
wf[wf_id].notifySuccess(instance, transition_list, result, args=args, kw=kw)
# Return result finally
return result
# Return result finally
return result
except:
pass
# Interactions should not be disabled during normal operation. Only in very # Interactions should not be disabled during normal operation. Only in very
# rare and specific cases like data migration. That's why it is implemented # rare and specific cases like data migration. That's why it is implemented
# with temporary monkey-patching, instead of slowing down __call__ with yet # with temporary monkey-patching, instead of slowing down __call__ with yet
...@@ -492,6 +527,43 @@ def getClassPropertyList(klass): ...@@ -492,6 +527,43 @@ def getClassPropertyList(klass):
if p not in ps_list]) if p not in ps_list])
return ps_list return ps_list
# =================== Workflow5 Project, Wenjie, Dec 2014 ======================
### this function will be used in /product/ERP5Type/dynamic/lazy_class.py
### in generatePortalTypeAccessors()
def intializePortalTypeERP5WorkflowMethod(ptype_klass, portal_workflow5):
### portal_workflow5 is the entire ERP5Workflow module, need to access the
### workflow_list from instance's portal type. So only the related erp5 workflow will be used.
wf5_module = aq_inner(portal_workflow5)
portal_type = portal_workflow5.getPortalObject().getDefaultModule(portal_type="portal_types")
pt = portal_type._getOb(ptype_klass.__name__)
#raise NotImplementedError (portal_type)
#raise NotImplementedError (wf5_module)#<Workflow Module at workflow_module>
for workflow5 in pt.workflow_list:
for tr in wf5_module._getOb(workflow5).objectValues(portal_type="Transition"):
tr_id = tr.id
method_id = tr_id
wf_id = workflow5
ptype_klass.security.declareProtected(Permissions.AccessContentsInformation,
method_id)
ptype_klass.registerWorkflowMethod(method_id, wf_id, tr_id)
method = getattr(ptype_klass, method_id)
# Wrap method
if not callable(method):
LOG('initializePortalTypeERP5WorkflowMethods', 100,
'WARNING! Can not initialize %s on %s' % \
(method_id, portal_type))
continue
if not isinstance(method, WorkflowMethod):
method = WorkflowMethod(method)
setattr(ptype_klass, method_id, method)
method.registerTransitionAlways(portal_type, wf_id, tr_id)
# =================== WF5 ======================================================
def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow): def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow):
"""We should now make sure workflow methods are defined """We should now make sure workflow methods are defined
and also make sure simulation state is defined.""" and also make sure simulation state is defined."""
...@@ -505,6 +577,8 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow): ...@@ -505,6 +577,8 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow):
dc_workflow_dict = dict() dc_workflow_dict = dict()
interaction_workflow_dict = dict() interaction_workflow_dict = dict()
# DCworkflow
for wf in portal_workflow.getWorkflowsFor(portal_type): for wf in portal_workflow.getWorkflowsFor(portal_type):
wf_id = wf.id wf_id = wf.id
wf_type = wf.__class__.__name__ wf_type = wf.__class__.__name__
...@@ -545,6 +619,7 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow): ...@@ -545,6 +619,7 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow):
storage[wf_id] = (transition_id_set, trigger_dict) storage[wf_id] = (transition_id_set, trigger_dict)
# Generate Workflow method:
for wf_id, v in dc_workflow_dict.iteritems(): for wf_id, v in dc_workflow_dict.iteritems():
transition_id_set, trigger_dict = v transition_id_set, trigger_dict = v
for tr_id, tdef in trigger_dict.iteritems(): for tr_id, tdef in trigger_dict.iteritems():
......
...@@ -46,6 +46,7 @@ from TranslationProviderBase import TranslationProviderBase ...@@ -46,6 +46,7 @@ from TranslationProviderBase import TranslationProviderBase
from sys import exc_info from sys import exc_info
from zLOG import LOG, ERROR from zLOG import LOG, ERROR
from Products.CMFCore.exceptions import zExceptions_Unauthorized from Products.CMFCore.exceptions import zExceptions_Unauthorized
from types import NoneType
def getCurrentUserIdOrAnonymousToken(): def getCurrentUserIdOrAnonymousToken():
"""Return connected user_id or simple token for """Return connected user_id or simple token for
...@@ -421,10 +422,9 @@ class ERP5TypeInformation(XMLObject, ...@@ -421,10 +422,9 @@ class ERP5TypeInformation(XMLObject,
for workflow5 in self.getTypeWorkflowList(): for workflow5 in self.getTypeWorkflowList():
workflow_module = portal.getDefaultModule(portal_type="Workflow") workflow_module = portal.getDefaultModule(portal_type="Workflow")
if workflow_module is not None: workflow5 = workflow_module._getOb(workflow5)
workflow5 = workflow_module._getOb(workflow5) workflow5.initializeDocument(ob)
workflow5.initializeDocument(ob)
if not temp_object: if not temp_object:
init_script = self.getTypeInitScriptId() init_script = self.getTypeInitScriptId()
...@@ -531,6 +531,7 @@ class ERP5TypeInformation(XMLObject, ...@@ -531,6 +531,7 @@ class ERP5TypeInformation(XMLObject,
""" """
Return all the properties of the Portal Type Return all the properties of the Portal Type
""" """
### cls's class is PortalTypeMetaClass defined in ERP5Type/dynamic/lazy_class.py
cls = self.getPortalObject().portal_types.getPortalTypeClass(self.getId()) cls = self.getPortalObject().portal_types.getPortalTypeClass(self.getId())
return_set = set() return_set = set()
for property_dict in cls.getAccessorHolderPropertyList(content=True): for property_dict in cls.getAccessorHolderPropertyList(content=True):
......
...@@ -7,7 +7,7 @@ from Products.ERP5Type.Accessor.Constant import Getter as ConstantGetter ...@@ -7,7 +7,7 @@ from Products.ERP5Type.Accessor.Constant import Getter as ConstantGetter
from Products.ERP5Type.Globals import InitializeClass from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Base import Base as ERP5Base from Products.ERP5Type.Base import Base as ERP5Base
from . import aq_method_lock from . import aq_method_lock
from Products.ERP5Type.Base import PropertyHolder, initializePortalTypeDynamicWorkflowMethods from Products.ERP5Type.Base import PropertyHolder, initializePortalTypeDynamicWorkflowMethods, intializePortalTypeERP5WorkflowMethod
from Products.ERP5Type.Utils import UpperCase from Products.ERP5Type.Utils import UpperCase
from Products.ERP5Type.Core.CategoryProperty import CategoryProperty from Products.ERP5Type.Core.CategoryProperty import CategoryProperty
from ExtensionClass import ExtensionClass, pmc_init_of from ExtensionClass import ExtensionClass, pmc_init_of
...@@ -266,6 +266,25 @@ class PortalTypeMetaClass(GhostBaseMetaClass, PropertyHolder): ...@@ -266,6 +266,25 @@ class PortalTypeMetaClass(GhostBaseMetaClass, PropertyHolder):
else: else:
initializePortalTypeDynamicWorkflowMethods(cls, portal_workflow) initializePortalTypeDynamicWorkflowMethods(cls, portal_workflow)
# ================== Workflow5 Project, Wenjie, Dec 2014 =======================
#raise NotImplementedError (cls.__name__) # Category Property
### the ERP5Workflow list is defined in ERP5Type, only try to get erp5workflow
### when it's an erp5workflow related type.
if cls.__name__ == "Object Type":
portal_workflow5 = site.getDefaultModule(portal_type="Workflow")
#raise NotImplementedError (portal_workflow5) #<Workflow Module at workflow_module>
#raise NotImplementedError (cls.__module__) #<class 'erp5.portal_type.Category Property'>
if portal_workflow5 is None:
LOG("ERP5Type.Dynamic", WARNING,
"no workflow5 methods for %s"
% cls.__name__)
else:
intializePortalTypeERP5WorkflowMethod(cls, portal_workflow5)
# ================== WF5 =======================================================
# portal type group methods, isNodeType, isResourceType... # portal type group methods, isNodeType, isResourceType...
from Products.ERP5Type.ERP5Type import ERP5TypeInformation from Products.ERP5Type.ERP5Type import ERP5TypeInformation
# XXX possible optimization: # XXX possible optimization:
......
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