diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
index 5bce84346f0b17a77ded48a3faef0aba222b0d3a..7b9d127353d70d4cbf77116543130dd0a2fefd05 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
@@ -81,6 +81,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataStoreDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IPersonDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleTypeDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.ServiceConversationsThreadContext;
 import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
 import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
 import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSServiceConversational;
@@ -1454,6 +1455,8 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements
                 injectPerson(sessionForEntityOperation, userId);
             }
 
+            ServiceConversationsThreadContext.setProgressListener(progressListener);
+
             long spacesCreated =
                     createSpaces(sessionForEntityOperation, operationDetails, progressListener);
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ServiceConversationsThreadContext.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ServiceConversationsThreadContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..55c292fd19ecf40030421790133c563f0dfc97c6
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ServiceConversationsThreadContext.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server.dataaccess;
+
+import ch.systemsx.cisd.common.conversation.IProgressListener;
+
+/**
+ * The class contains the logic for communication beetween Hibernate interceptors, which should send
+ * service conversation updates, and parts of applications that use service conversations, but don't
+ * have acces to the Hibernate objects.
+ * <p>
+ * It lets the owner of service conversation store the information about it in the thread local
+ * variable, from which the interceptor can later read it.
+ * 
+ * @author Jakub Straszewski
+ */
+public class ServiceConversationsThreadContext
+{
+    private static ThreadLocal<IProgressListener> progressListener;
+
+    static
+    {
+        progressListener = new ThreadLocal<IProgressListener>();
+    }
+
+    /**
+     * Store progress listener in a thread local context
+     */
+    public static void setProgressListener(IProgressListener listener)
+    {
+        progressListener.set(listener);
+    }
+
+    /**
+     * Remove information about progress listener from the thread local context.
+     */
+    public static void unsetProgressListener()
+    {
+        progressListener.remove();
+    }
+
+    /**
+     * Read the progress listener from the thread local context
+     */
+    public static IProgressListener getProgressListener()
+    {
+        return progressListener.get();
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityValidationInterceptor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityValidationInterceptor.java
index 61ea338acfd85dc6b2435081c5d2d78c122c25a2..3e2d6e7100abb4693d5a55ed619756ae0f221895 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityValidationInterceptor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityValidationInterceptor.java
@@ -27,8 +27,10 @@ import org.hibernate.Interceptor;
 import org.hibernate.Transaction;
 import org.hibernate.type.Type;
 
+import ch.systemsx.cisd.common.conversation.IProgressListener;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.ServiceConversationsThreadContext;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.DynamicPropertyEvaluator;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.IDynamicPropertyEvaluator;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.EntityAdaptorFactory;
@@ -61,6 +63,10 @@ public class EntityValidationInterceptor extends EmptyInterceptor implements
         this.callback = callback;
         this.daoFactory = daoFactory;
         initializeLists();
+
+        totalEntitiesToValidateCount = 0;
+
+        entitiesValidatedCount = 0;
     }
 
     IHibernateTransactionManagerCallback callback;
@@ -80,10 +86,25 @@ public class EntityValidationInterceptor extends EmptyInterceptor implements
 
     Queue<IEntityInformationWithPropertiesHolder> entitiesToValidate;
 
+    /**
+     * WE get information about progress listener, form the caller of updates. Luckily the
+     * onFlushDirty and onSave hooks are executed in the same thread as the caller.
+     * <p>
+     * The beforeTransactionCompletionHook is called in the separate thread, therefore we persist
+     * progress listener in a designated variable
+     */
+    IProgressListener progressListener;
+
+    int totalEntitiesToValidateCount;
+
+    int entitiesValidatedCount;
+
     @Override
     public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
             Type[] types)
     {
+        updateListener();
+
         if (entity instanceof IEntityInformationWithPropertiesHolder)
         {
             newEntity((IEntityInformationWithPropertiesHolder) entity);
@@ -91,10 +112,17 @@ public class EntityValidationInterceptor extends EmptyInterceptor implements
         return false;
     }
 
+    private void updateListener()
+    {
+        progressListener = ServiceConversationsThreadContext.getProgressListener();
+    }
+
     @Override
     public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
             Object[] previousState, String[] propertyNames, Type[] types)
     {
+        updateListener();
+
         if (entity instanceof IEntityInformationWithPropertiesHolder)
         {
             modifiedEntity((IEntityInformationWithPropertiesHolder) entity);
@@ -143,15 +171,18 @@ public class EntityValidationInterceptor extends EmptyInterceptor implements
             IEntityInformationWithPropertiesHolder entity, boolean isNewEntity)
     {
         String result = null;
-
         try
         {
+            if (progressListener != null)
+            {
+                progressListener.update("Validation of entities", totalEntitiesToValidateCount,
+                        entitiesValidatedCount);
+            }
             result = calculate(script, entity, isNewEntity);
         } catch (Throwable e)
         {
             callback.rollbackTransaction(tx, "Validation of " + entityDescription(entity)
                     + " resulted in error. " + e.getMessage());
-            e.printStackTrace();
         }
         if (result != null)
         {
@@ -181,11 +212,13 @@ public class EntityValidationInterceptor extends EmptyInterceptor implements
 
     private void newEntity(IEntityInformationWithPropertiesHolder entity)
     {
+        totalEntitiesToValidateCount++;
         newEntities.add(entity);
     }
 
     private void validatedEntity(IEntityInformationWithPropertiesHolder entity)
     {
+        entitiesValidatedCount++;
         validatedEntities.add(entity);
     }
 
@@ -193,6 +226,7 @@ public class EntityValidationInterceptor extends EmptyInterceptor implements
     {
         if (false == newEntities.contains(entity))
         {
+            totalEntitiesToValidateCount++;
             modifiedEntities.add(entity);
         }
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityTypeDAOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityTypeDAOTest.java
index f85a688cb42d983d16fccb8d4d14284e57998f68..dd54d0782305191097a6ef6007e07969d766ad56 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityTypeDAOTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/EntityTypeDAOTest.java
@@ -139,7 +139,7 @@ public final class EntityTypeDAOTest extends AbstractDAOTest
     public final void testListMaterialTypes()
     {
         final IEntityTypeDAO entityTypeDAO = daoFactory.getEntityTypeDAO(EntityKind.MATERIAL);
-        assertEquals(8, entityTypeDAO.listEntityTypes().size());
+        assertEquals(9, entityTypeDAO.listEntityTypes().size());
     }
 
     @Test(dependsOnMethods = "testListMaterialTypes")
diff --git a/openbis/sourceTest/sql/postgresql/120/039=material_type_property_types.tsv b/openbis/sourceTest/sql/postgresql/120/039=material_type_property_types.tsv
index 14be4e6c44c2018df78bdf3a60534b92ea743867..e9fe833436e993e5bf31e0f0b61f72b73c7262db 100644
--- a/openbis/sourceTest/sql/postgresql/120/039=material_type_property_types.tsv
+++ b/openbis/sourceTest/sql/postgresql/120/039=material_type_property_types.tsv
@@ -16,3 +16,5 @@
 22	6	15	f	f	2008-11-05 09:18:32.512+01	2	\N	2	\N	t
 23	8	1	t	t	2008-11-05 09:18:32.512+01	2	\N	1	\N	t
 24	8	26	f	f	2012-03-13 09:18:32.512+01	2	\N	2	\N	t
+25	9	2	t	t	2008-11-05 09:18:00.622+01	1	\N	1	\N	t
+26	9	1	f	t	2008-11-05 09:18:00.622+01	1	\N	2	\N	t
\ No newline at end of file
diff --git a/openbis/sourceTest/sql/postgresql/120/040=material_types.tsv b/openbis/sourceTest/sql/postgresql/120/040=material_types.tsv
index 5365c9e6141e2ba3a0453ef7e63b8dff257df7d6..ad2b89ce5a917b824c0a1ead8def050d823904b4 100644
--- a/openbis/sourceTest/sql/postgresql/120/040=material_types.tsv
+++ b/openbis/sourceTest/sql/postgresql/120/040=material_types.tsv
@@ -1,8 +1,9 @@
 1	VIRUS	Virus	1	2009-03-23 15:34:44.462776+01	\N
 2	CELL_LINE	Cell Line or Cell Culture. The growing of cells under controlled conditions.	1	2009-03-23 15:34:44.462776+01	\N
 3	GENE	Gene	1	2009-03-23 15:34:44.462776+01	\N
-5	CONTROL	Control of a control layout	1	2009-03-23 15:34:44.462776+01	\N
+5	CONTROL	Control of a control layout	1	2009-03-23 15:34:44.462776+01	5
 6	BACTERIUM	Bacterium	1	2009-03-23 15:34:44.462776+01	\N
 7	COMPOUND	Compound	1	2009-03-23 15:34:44.462776+01	\N
 4	SIRNA	Oligo nucleotide	1	2009-03-23 15:34:44.462776+01	\N
 8	SELF_REF	Self Referencing Material	1	2012-03-13 15:34:44.462776+01	\N
+9	SLOW_GENE	Slowly validating material	1	2009-03-23 15:34:44.462776+01	10
diff --git a/openbis/sourceTest/sql/postgresql/120/057=scripts.tsv b/openbis/sourceTest/sql/postgresql/120/057=scripts.tsv
index 86b1ac13a3eea129a32570ae90a731aa3a2b22d0..f5337aa5e81fabbab1ae6dea35b88b6c11130637 100644
--- a/openbis/sourceTest/sql/postgresql/120/057=scripts.tsv
+++ b/openbis/sourceTest/sql/postgresql/120/057=scripts.tsv
@@ -7,3 +7,4 @@
 7	1	validateUpdateFAIL	\N	def validate(entity, isNew):\n  if (not isNew):\n    return "Cannot update this entity"\n 	2010-10-27 15:16:48.994831+02	2	\N	ENTITY_VALIDATION
 8	1	validateChildren	\N	def validate(entity, isNew):\n  for childRelation in entity.entityPE().getChildRelationships():\n    requestValidation(childRelation.getChildSample())	2010-10-27 15:16:48.994831+02	2	\N	ENTITY_VALIDATION
 9	1	code_date	\N	"%s %s" % (entity.code(), str(currentDate().getTime()))	2010-10-27 15:16:48.994831+02	2	\N	DYNAMIC_PROPERTY
+10	1	waitOK	\N	import time;\ndef validate(entity, isNew):\n  time.sleep(1);\n 	2010-10-27 15:16:48.994831+02	2	\N	ENTITY_VALIDATION