diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index 98be0b25ceef9a385de5a325b68e938831f27900..c01b9a07f104225bb0e203e184cbbdc7da74a185 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -26,6 +26,7 @@ import java.util.Date;
 import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -93,6 +94,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.IDyna
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.DynamicPropertyCalculator;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.EntityAdaptorFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.EntityValidationCalculator;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.EntityValidationCalculator.IValidationRequestDelegate;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IEntityAdaptor;
 import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.EncapsulatedCommonServer;
 import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.MasterDataRegistrationScriptRunner;
@@ -1917,8 +1919,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     {
         List<EntityTypePE> types = new ArrayList<EntityTypePE>();
         if ((entityKind.equals(EntityKind.SAMPLE) || entityKind.equals(EntityKind.DATA_SET) || entityKind
-                .equals(EntityKind.MATERIAL))
-                && EntityType.isDefinedInFileEntityTypeCode(type))
+                .equals(EntityKind.MATERIAL)) && EntityType.isDefinedInFileEntityTypeCode(type))
         {
             types.addAll(getDAOFactory().getEntityTypeDAO(
                     DtoConverters.convertEntityKind(entityKind)).listEntityTypes());
@@ -2496,14 +2497,55 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         IEntityInformationWithPropertiesHolder entity = getEntity(info, session);
         try
         {
+            final List<String> objectsWhichValidationWouldBeForced = new LinkedList<String>();
+
+            // TODO: refactor the check for type of entity requested for validation to the code of
+            // the caller to avoid duplication beetween here and EntityValidationInterceptor
             EntityValidationCalculator calculator =
-                    EntityValidationCalculator.create(info.getScript());
+                    EntityValidationCalculator.create(info.getScript(),
+                            new IValidationRequestDelegate()
+                                {
+                                    @Override
+                                    public void requestValidation(Object o)
+                                    {
+                                        if (o == null)
+                                        {
+                                            return;
+                                        }
+                                        if (!(o instanceof IEntityInformationWithPropertiesHolder))
+                                        {
+                                            throw new IllegalArgumentException(
+                                                    "Would try to force validation if illegal object "
+                                                            + o.getClass());
+                                        }
+                                        objectsWhichValidationWouldBeForced
+                                                .add(((IEntityInformationWithPropertiesHolder) o)
+                                                        .getIdentifier());
+                                    }
+                                });
             IDynamicPropertyEvaluator evaluator =
                     new DynamicPropertyEvaluator(getDAOFactory(), null);
             IEntityAdaptor adaptor = EntityAdaptorFactory.create(entity, evaluator);
             calculator.setEntity(adaptor);
             calculator.setIsNewEntity(info.isNew());
-            return calculator.evalAsString();
+            String result = calculator.evalAsString();
+
+            if (result != null)
+            {
+                return "Validation fail: " + result;
+            } else
+            {
+                result = "Validation OK";
+                if (objectsWhichValidationWouldBeForced.size() > 0)
+                {
+                    result += "\n\nOther entities would be forced to validate:\n";
+                    for (Object o : objectsWhichValidationWouldBeForced)
+                    {
+                        result += "  " + o + "\n";
+                    }
+                }
+                return result;
+            }
         } catch (Throwable e)
         {
             // return error message if there is a problem with evaluation
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 82fea297b59dfd60abdf5aa4f840a8c61ce256f2..84bc81bad255d9527c40cf9a21cae73fc9076ea0 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
@@ -18,6 +18,8 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 
 import java.io.Serializable;
 import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
 import java.util.Set;
 
 import org.hibernate.EmptyInterceptor;
@@ -31,6 +33,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.Dynam
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.IDynamicPropertyEvaluator;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.EntityAdaptorFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.EntityValidationCalculator;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.EntityValidationCalculator.IValidationRequestDelegate;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IEntityAdaptor;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ServiceVersionHolder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder;
@@ -45,7 +48,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.ScriptPE;
  * 
  * @author Jakub Straszewski
  */
-public class EntityValidationInterceptor extends EmptyInterceptor
+public class EntityValidationInterceptor extends EmptyInterceptor implements
+        IValidationRequestDelegate
 {
     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
@@ -61,17 +65,29 @@ public class EntityValidationInterceptor extends EmptyInterceptor
 
     IHibernateTransactionManagerCallback callback;
 
+    /*
+     * During the transaction the new objects are inserted into the newEntities and
+     * mofidiedEntities. During the validation phase, first all new entities are validated, then the
+     * remaining, which consists of a modified entities, and the entities which were explicitly
+     * marked for validation by validation scripts. We keep the track of validated entities in the
+     * set, and keep the entities we still have to validate in entitiesToValidate.
+     */
+    // TODO: refactor - there are too many collections here
     Set<IEntityInformationWithPropertiesHolder> modifiedEntities;
 
     Set<IEntityInformationWithPropertiesHolder> newEntities;
 
+    Set<IEntityInformationWithPropertiesHolder> validatedEntities;
+
+    Queue<IEntityInformationWithPropertiesHolder> entitiesToValidate;
+
     @Override
     public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
             Type[] types)
     {
         if (entity instanceof IEntityInformationWithPropertiesHolder)
         {
-            newEntity(entity);
+            newEntity((IEntityInformationWithPropertiesHolder) entity);
         }
         return false;
     }
@@ -82,7 +98,7 @@ public class EntityValidationInterceptor extends EmptyInterceptor
     {
         if (entity instanceof IEntityInformationWithPropertiesHolder)
         {
-            modifiedEntity(entity);
+            modifiedEntity((IEntityInformationWithPropertiesHolder) entity);
         }
         return false;
     }
@@ -90,31 +106,33 @@ public class EntityValidationInterceptor extends EmptyInterceptor
     @Override
     public void beforeTransactionCompletion(Transaction tx)
     {
-        for (IEntityInformationWithPropertiesHolder entity : newEntities)
+        validateNewEntities(tx);
+
+        for (IEntityInformationWithPropertiesHolder entity : modifiedEntities)
         {
-            validateNewEntity(tx, entity);
+            entitiesToValidate.add(entity);
         }
 
-        for (IEntityInformationWithPropertiesHolder entity : modifiedEntities)
+        while (entitiesToValidate.size() > 0)
         {
-            validateModifiedEntity(tx, entity);
+            IEntityInformationWithPropertiesHolder entity = entitiesToValidate.remove();
+            validateEntity(tx, entity, false);
         }
-    }
 
-    private void validateModifiedEntity(Transaction tx,
-            IEntityInformationWithPropertiesHolder entity)
-    {
-        validateEntity(tx, entity, false);
     }
 
-    private void validateNewEntity(Transaction tx, IEntityInformationWithPropertiesHolder entity)
+    private void validateNewEntities(Transaction tx)
     {
-        validateEntity(tx, entity, true);
+        for (IEntityInformationWithPropertiesHolder entity : newEntities)
+        {
+            validateEntity(tx, entity, true);
+        }
     }
 
     private void validateEntity(Transaction tx, IEntityInformationWithPropertiesHolder entity,
             boolean isNewEntity)
     {
+        validatedEntity(entity);
         ScriptPE validationScript = entity.getEntityType().getValidationScript();
         if (validationScript != null)
         {
@@ -154,7 +172,7 @@ public class EntityValidationInterceptor extends EmptyInterceptor
             boolean isNewEntity)
     {
         EntityValidationCalculator calculator =
-                EntityValidationCalculator.create(script.getScript());
+                EntityValidationCalculator.create(script.getScript(), this);
         IDynamicPropertyEvaluator evaluator = new DynamicPropertyEvaluator(daoFactory, null);
         IEntityAdaptor adaptor = EntityAdaptorFactory.create(entity, evaluator);
         calculator.setEntity(adaptor);
@@ -162,22 +180,21 @@ public class EntityValidationInterceptor extends EmptyInterceptor
         return calculator.evalAsString();
     }
 
-    private void newEntity(Object entity)
+    private void newEntity(IEntityInformationWithPropertiesHolder entity)
     {
-        newEntities.add((IEntityInformationWithPropertiesHolder) entity);
+        newEntities.add(entity);
     }
 
-    private void modifiedEntity(Object entity)
+    private void validatedEntity(IEntityInformationWithPropertiesHolder entity)
     {
-        addModifiedEntityToSet((IEntityInformationWithPropertiesHolder) entity, modifiedEntities,
-                newEntities);
+        validatedEntities.add(entity);
     }
 
-    private <T> void addModifiedEntityToSet(T entity, Set<T> modifiedSet, Set<T> newSet)
+    private void modifiedEntity(IEntityInformationWithPropertiesHolder entity)
     {
-        if (false == newSet.contains(entity))
+        if (false == newEntities.contains(entity))
         {
-            modifiedSet.add(entity);
+            modifiedEntities.add(entity);
         }
     }
 
@@ -185,6 +202,36 @@ public class EntityValidationInterceptor extends EmptyInterceptor
     {
         modifiedEntities = new HashSet<IEntityInformationWithPropertiesHolder>();
         newEntities = new HashSet<IEntityInformationWithPropertiesHolder>();
+        validatedEntities = new HashSet<IEntityInformationWithPropertiesHolder>();
+        entitiesToValidate = new LinkedList<IEntityInformationWithPropertiesHolder>();
+    }
+
+    @Override
+    public void requestValidation(Object entity)
+    {
+        if (entity == null)
+        {
+            return;
+        }
+
+        if (false == entity instanceof IEntityInformationWithPropertiesHolder)
+        {
+            throw new IllegalArgumentException(
+                    "Trying to force the validation of an object of invalid type "
+                            + entity.getClass());
+        }
+
+        if (validatedEntities.contains(entity) || newEntities.contains(entity)
+                || modifiedEntities.contains(entity))
+        {
+            // forcing validation of entity already listed for validation
+        } else
+        {
+            // we update modified entities to know that we will validate this entity
+            modifiedEntities.add((IEntityInformationWithPropertiesHolder) entity);
+            // we add to the actual validation queue
+            entitiesToValidate.add((IEntityInformationWithPropertiesHolder) entity);
+        }
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/EntityValidationCalculator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/EntityValidationCalculator.java
index 27cc0035bba3584b6c8b82d2fc5df0972440a238..a438eab7d8fdff11cbeca4b1b4b4d5dfd10e2b44 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/EntityValidationCalculator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/dynamic_property/calculator/EntityValidationCalculator.java
@@ -32,25 +32,41 @@ public class EntityValidationCalculator extends AbstractCalculator
     private static final String INVOKE_CALCULATE_EXPR = "validate(" + ENTITY_VARIABLE_NAME + ", "
             + IS_NEW_ENTITY_VARIABLE_NAME + ")";
 
+    private static final String REQUEST_DELEGATE_VARIABLE = "__entityValidationRequestDelegate";
+
+    private static final String VALIDATION_REQUEST_FUNCTION = "def requestValidation(entity):\n  "
+            + REQUEST_DELEGATE_VARIABLE + ".requestValidation(entity)\n";
+
+    public interface IValidationRequestDelegate
+    {
+        public void requestValidation(Object o);
+    }
+
+    private IValidationRequestDelegate validationRequested;
+
     /**
      * Creates a calculator for given <code>expression</code>.
      * <p>
      * The script is expected to contain validate method with two parameters: "entity" and
      * "isNewEntity"
      */
-    public static EntityValidationCalculator create(String expression)
+    public static EntityValidationCalculator create(String expression,
+            IValidationRequestDelegate validationRequestedDelegate)
     {
         String initialScript = getBasicInitialScript();
         initialScript += importFunctions(EntityValidationCalculator.class) + NEWLINE;
+        initialScript += VALIDATION_REQUEST_FUNCTION + NEWLINE;
         initialScript += expression;
         String calculatedExpression = INVOKE_CALCULATE_EXPR;
         return new EntityValidationCalculator(new Evaluator(calculatedExpression, Math.class,
-                initialScript));
+                initialScript), validationRequestedDelegate);
     }
 
-    public EntityValidationCalculator(Evaluator evaluator)
+    public EntityValidationCalculator(Evaluator evaluator,
+            IValidationRequestDelegate validationRequested)
     {
         super(evaluator);
+        evaluator.set(REQUEST_DELEGATE_VARIABLE, validationRequested);
     }
 
     public void setEntity(IEntityAdaptor entity)