Commit 34e13b7e authored by Sebastien Robin's avatar Sebastien Robin Committed by Georgios Dagkakis

BusinessTemplate: fix installation of portal type and instance of that type

Such error was raised :
BrokenModified: Can't change broken objects

We were installing a broken object even though the portal type was just
installed. This was due to a missing reset of components.
parent 889d73b9
......@@ -62,6 +62,7 @@ from Products.ERP5Type.Utils import readLocalTest, \
from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.dynamic.lazy_class import ERP5BaseBroken
from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModules
from Products.ERP5Type.Core.PropertySheet import PropertySheet as PropertySheetDocument
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
......@@ -656,6 +657,21 @@ class BaseTemplateItem(Implicit, Persistent):
else:
return context
def _resetDynamicModules(self):
# before any import, flush all ZODB caches to force a DB reload
# otherwise we could have objects trying to get commited while
# holding reference to a class that is no longer the same one as
# the class in its import location and pickle doesn't tolerate it.
# First we do a savepoint to dump dirty objects to temporary
# storage, so that all references to them can be freed.
transaction.savepoint(optimistic=True)
# Then we need to flush from all caches, not only the one from this
# connection
portal = self.getPortalObject()
portal._p_jar.db().cacheMinimize()
synchronizeDynamicModules(portal, force=True)
gc.collect()
class ObjectTemplateItem(BaseTemplateItem):
"""
This class is used for generic objects and as a subclass.
......@@ -1001,6 +1017,10 @@ class ObjectTemplateItem(BaseTemplateItem):
root_document_path = '/%s/%s' % (portal.getId(), root_path)
recursiveUnindex(catalog, item_path, root_document_path)
def fixBrokenObject(self, obj):
if isinstance(obj, ERP5BaseBroken):
self._resetDynamicModules()
def install(self, context, trashbin, **kw):
self.beforeInstall()
update_dict = kw.get('object_to_update')
......@@ -1109,6 +1129,7 @@ class ObjectTemplateItem(BaseTemplateItem):
# install object
obj = self._objects[path]
self.fixBrokenObject(obj)
# XXX Following code make Python Scripts compile twice, because
# _getCopy returns a copy without the result of the compilation.
# A solution could be to add a specific _getCopy method to
......@@ -2165,7 +2186,6 @@ class PortalTypeTemplateItem(ObjectTemplateItem):
self._workflow_chain_archive[portal_type]
context.portal_workflow.manage_changeWorkflows(default_chain,
props=chain_dict)
# XXX : this method is kept temporarily, but can be removed once all bt5 are
# re-exported with separated workflow-chain information
def _importFile(self, file_name, file):
......@@ -3524,21 +3544,6 @@ class FilesystemDocumentTemplateItem(BaseTemplateItem):
{self._getKey(path) : ['Removed', self.__class__.__name__[:-12]]})
return modified_object_list
def _resetDynamicModules(self):
# before any import, flush all ZODB caches to force a DB reload
# otherwise we could have objects trying to get commited while
# holding reference to a class that is no longer the same one as
# the class in its import location and pickle doesn't tolerate it.
# First we do a savepoint to dump dirty objects to temporary
# storage, so that all references to them can be freed.
transaction.savepoint(optimistic=True)
# Then we need to flush from all caches, not only the one from this
# connection
portal = self.getPortalObject()
portal._p_jar.db().cacheMinimize()
synchronizeDynamicModules(portal, force=True)
gc.collect()
def install(self, context, trashbin, **kw):
update_dict = kw.get('object_to_update')
force = kw.get('force')
......
......@@ -39,6 +39,7 @@ from Products.ERP5Type.tests.Sequence import SequenceList, Sequence
from urllib import pathname2url
from Products.ERP5Type.Globals import PersistentMapping
from Products.CMFCore.Expression import Expression
from Products.ERP5Type.dynamic.lazy_class import ERP5BaseBroken
from Products.ERP5Type.tests.utils import LogInterceptor
from Products.ERP5Type.Workflow import addWorkflowByType
import shutil
......@@ -6337,6 +6338,32 @@ class TestBusinessTemplate(BusinessTemplateMixin):
# check both File instances no longer behave like being overriden
self.assertFalse(getattr(portal.another_file, 'isClassOverriden', False))
def test_168_CheckPortalTypeAndPathInSameBusinessTemplate(self):
"""
Make sure we can define a portal type and instance of that portal type
in same bt. It already happened that this failed with error :
BrokenModified: Can't change broken objects
It might sound similar to test_167, but we had cases not working even
though test_167 was running fine (due to additional steps that were
doing more reset of components)
"""
template_tool = self.portal.portal_templates
bt_path = os.path.join(os.path.dirname(__file__), 'test_data',
'BusinessTemplate_test_168_CheckPortalTypeAndPathInSameBusinessTemplate')
bt = template_tool.download(bt_path)
foo_in_bt = bt._path_item._objects["foo"]
# Force evaluation of a method to force unghosting of the class
getattr(foo_in_bt, "getTitle", None)
self.assertTrue(isinstance(foo_in_bt, ERP5BaseBroken))
self.commit()
bt.install(force=1)
self.commit()
foo_in_portal = self.portal.foo
self.assertFalse(isinstance(foo_in_portal, ERP5BaseBroken))
self.assertEqual("Foo", foo_in_portal.getPortalType())
self.uninstallBusinessTemplate('test_168_CheckPortalTypeAndPathInSameBusinessTemplate')
def test_type_provider(self):
self.portal.newContent(id='dummy_type_provider', portal_type="Types Tool")
type_provider = self.portal.dummy_type_provider
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Foo" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>foo</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>Foo</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Foo Type</string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>XMLObject</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
test_168_CheckPortalTypeAndPathInSameBusinessTemplate
\ No newline at end of file
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