diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/property/EntityAdaptorFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/property/EntityAdaptorFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c64d9935dd459213c9f376bb86419d06dabc556
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/calculator/property/EntityAdaptorFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 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.client.web.server.calculator.property;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+
+/**
+ * Factory of adaptors implementing {@link IEntityAdaptor}.
+ * 
+ * @author Piotr Buczek
+ */
+public class EntityAdaptorFactory
+{
+    /** Returns an adaptor for specified entity based on its kind. */
+    public static IEntityAdaptor create(IEntityInformationWithPropertiesHolder entity)
+    {
+        switch (entity.getEntityKind())
+        {
+            case SAMPLE:
+                return new SampleAdaptor((SamplePE) entity);
+            case EXPERIMENT:
+                return new ExperimentAdaptor((ExperimentPE) entity);
+            case DATA_SET:
+                return new ExternalDataAdaptor((ExternalDataPE) entity);
+            case MATERIAL:
+                return new MaterialAdaptor((MaterialPE) entity);
+            default:
+                throw new UnsupportedOperationException(""); // can't happen
+        }
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/ColumnSortUtils.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/ColumnSortUtils.java
index c04a9b43a944b24a93d304d3c3eedbe8583fd187..63b008d942202eef8b89bebef4e46ffd9d2419c2 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/ColumnSortUtils.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/ColumnSortUtils.java
@@ -40,7 +40,7 @@ class ColumnSortUtils
         // compare code and identifier columns with a special alphanum comparator
         final Comparator<GridRowModel<T>> comparator =
                 isAlphanum(sortField) ? createAlphanumComparator(sortField)
-                        : createDefaiultComparator(sortField);
+                        : createDefaultComparator(sortField);
         return applySortDir(sortDir, comparator);
     }
 
@@ -52,8 +52,9 @@ class ColumnSortUtils
                 || field.getIdentifier().contains("IDENTIFIER");
     }
 
+    // TODO 2010-10-19, Piotr Buczek: extract common part with createAlphanumComparator
     @SuppressWarnings("unchecked")
-    private static <T> Comparator<GridRowModel<T>> createDefaiultComparator(
+    private static <T> Comparator<GridRowModel<T>> createDefaultComparator(
             final IColumnDefinition<T> sortField)
     {
         return new Comparator<GridRowModel<T>>()
@@ -66,7 +67,25 @@ class ColumnSortUtils
                     // treat null as minimal value
                     if (v1 == null)
                     {
-                        return -1;
+                        // error messages are bigger
+                        if (v2 == null)
+                        {
+                            String s1 = sortField.getValue(o1);
+                            String s2 = sortField.getValue(o2);
+                            if (s1 == null)
+                            {
+                                return -1;
+                            } else if (s2 == null)
+                            {
+                                return -1;
+                            } else
+                            {
+                                return s1.compareTo(s2);
+                            }
+                        } else
+                        {
+                            return -1;
+                        }
                     } else if (v2 == null)
                     {
                         return 1;
@@ -93,7 +112,25 @@ class ColumnSortUtils
                     // treat null as minimal value
                     if (v1 == null)
                     {
-                        return -1;
+                        // error messages are bigger
+                        if (v2 == null)
+                        {
+                            String s1 = sortField.getValue(o1);
+                            String s2 = sortField.getValue(o2);
+                            if (s1 == null)
+                            {
+                                return -1;
+                            } else if (s2 == null)
+                            {
+                                return -1;
+                            } else
+                            {
+                                return s1.compareTo(s2);
+                            }
+                        } else
+                        {
+                            return -1;
+                        }
                     } else if (v2 == null)
                     {
                         return 1;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
index 54471ef824ab050c294a79a3cdbc31fa1fc35253..acb53c3888897e3d5e47e46926983e30c2d0dd9c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
@@ -52,6 +52,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.IVocabularyTermDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.PersistencyResources;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.ICodeSequenceDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.IPermIdDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.IDynamicPropertyEvaluationScheduler;
 import ch.systemsx.cisd.openbis.generic.server.util.GroupIdentifierHelper;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE;
@@ -317,4 +318,9 @@ abstract class AbstractBusinessObject implements IDAOFactory
     {
         return daoFactory.getRelationshipTypeDAO();
     }
+
+    public IDynamicPropertyEvaluationScheduler getDynamicPropertyEvaluationScheduler()
+    {
+        return daoFactory.getDynamicPropertyEvaluationScheduler();
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java
index 5c2d9d823daf4565fea0f9613c8218f91298df14..10f7a1fbb23499a914f3e16f216e2803fa52529f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java
@@ -40,6 +40,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPropertyPE;
@@ -50,7 +51,6 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
-import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
@@ -106,19 +106,6 @@ public final class ExperimentBO extends AbstractBusinessObject implements IExper
         return (ExperimentTypePE) experimentType;
     }
 
-    @SuppressWarnings("unused")
-    private final void defineSampleProperties(final IEntityProperty[] experimentProperties)
-    {
-        final String experimentTypeCode = experiment.getExperimentType().getCode();
-        final List<ExperimentPropertyPE> properties =
-                propertiesConverter.convertProperties(experimentProperties, experimentTypeCode,
-                        experiment.getRegistrator());
-        for (final ExperimentPropertyPE property : properties)
-        {
-            experiment.addProperty(property);
-        }
-    }
-
     public final ExperimentPE getExperiment()
     {
         checkExperimentLoaded();
@@ -291,8 +278,8 @@ public final class ExperimentBO extends AbstractBusinessObject implements IExper
         experiment.setCode(experimentIdentifier.getExperimentCode());
         experiment.setRegistrator(registrator);
         defineExperimentType(newExperiment);
-        defineExperimentProperties(newExperiment.getExperimentTypeCode(), newExperiment
-                .getProperties(), registrator);
+        defineExperimentProperties(newExperiment.getExperimentTypeCode(),
+                newExperiment.getProperties(), registrator);
         defineExperimentProject(newExperiment, experimentIdentifier);
         experiment.setPermId(getPermIdDAO().createPermId());
         dataChanged = true;
@@ -377,8 +364,8 @@ public final class ExperimentBO extends AbstractBusinessObject implements IExper
 
     private void checkBusinessRules()
     {
-        propertiesConverter.checkMandatoryProperties(experiment.getProperties(), experiment
-                .getExperimentType());
+        propertiesConverter.checkMandatoryProperties(experiment.getProperties(),
+                experiment.getExperimentType());
     }
 
     private ExperimentIdentifier createExperimentIdentifier()
@@ -515,8 +502,8 @@ public final class ExperimentBO extends AbstractBusinessObject implements IExper
         if (missingSamples.size() > 0)
         {
             throw UserFailureException.fromTemplate(
-                    "Samples with following codes do not exist in the space '%s': '%s'.", group
-                            .getCode(), CollectionUtils.abbreviate(missingSamples, 10));
+                    "Samples with following codes do not exist in the space '%s': '%s'.",
+                    group.getCode(), CollectionUtils.abbreviate(missingSamples, 10));
         } else
         {
             return samples;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java
index 629dd5bc04c534b3692623ac11542a491d00ce6f..ec88c63f32f2f18535325d407f7c3cf6f9fd2dab 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess;
 
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.ICodeSequenceDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.IPermIdDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.IDynamicPropertyEvaluationScheduler;
 import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
 
 /**
@@ -98,4 +99,7 @@ public interface IDAOFactory extends IAuthorizationDAOFactory
     /** Returns an implementation of {@link IAuthorizationGroupDAO}. */
     public IAuthorizationGroupDAO getAuthorizationGroupDAO();
 
+    /** Returns an implementation of {@link IDynamicPropertyEvaluationScheduler}. */
+    public IDynamicPropertyEvaluationScheduler getDynamicPropertyEvaluationScheduler();
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java
index 6d3a028572ff77e0161ebabf8bec11af5b04e07b..f8a432e3849bae24e8d9b52f36c4e39bee7339fc 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java
@@ -43,6 +43,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.IRelationshipTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IRoleAssignmentDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.PersistencyResources;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.IDynamicPropertyEvaluationScheduler;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
 import ch.systemsx.cisd.openbis.generic.shared.util.UuidUtil;
@@ -87,7 +88,8 @@ public class AuthorizationDAOFactory implements IAuthorizationDAOFactory
 
     public AuthorizationDAOFactory(final DatabaseConfigurationContext context,
             final SessionFactory sessionFactory,
-            final IFullTextIndexUpdateScheduler indexUpdateScheduler)
+            final IFullTextIndexUpdateScheduler indexUpdateScheduler,
+            final IDynamicPropertyEvaluationScheduler dynamicPropertyEvaluationScheduler)
     {
         persistencyResources = new PersistencyResources(context, sessionFactory);
         databaseInstancesDAO = new DatabaseInstanceDAO(sessionFactory);
@@ -98,7 +100,9 @@ public class AuthorizationDAOFactory implements IAuthorizationDAOFactory
         externalDataDAO = new ExternalDataDAO(sessionFactory, homeDatabaseInstance);
         experimentDAO = new ExperimentDAO(sessionFactory, homeDatabaseInstance);
         projectDAO = new ProjectDAO(sessionFactory, homeDatabaseInstance);
-        sampleDAO = new SampleDAO(sessionFactory, homeDatabaseInstance, indexUpdateScheduler);
+        sampleDAO =
+                new SampleDAO(sessionFactory, homeDatabaseInstance, indexUpdateScheduler,
+                        dynamicPropertyEvaluationScheduler);
         gridCustomFilterDAO = new GridCustomFilterDAO(sessionFactory, homeDatabaseInstance);
         gridCustomColumnDAO = new GridCustomColumnDAO(sessionFactory, homeDatabaseInstance);
         queryDAO = new QueryDAO(sessionFactory, homeDatabaseInstance);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java
index 37dd4161e67de831cc46e005763addfb56deeb70..bbb40399b905b995f6a4db60e6ec9cb9065a6d8d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java
@@ -40,6 +40,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IScriptDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IVocabularyDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IVocabularyTermDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.IDynamicPropertyEvaluationScheduler;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.HibernateSearchContext;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
@@ -58,6 +59,8 @@ public final class DAOFactory extends AuthorizationDAOFactory implements IDAOFac
         SpringEoDSQLExceptionTranslator.activate();
     }
 
+    private final IDynamicPropertyEvaluationScheduler dynamicPropertyEvaluationScheduler;
+
     private final ISampleTypeDAO sampleTypeDAO;
 
     private final IHibernateSearchDAO hibernateSearchDAO;
@@ -98,9 +101,12 @@ public final class DAOFactory extends AuthorizationDAOFactory implements IDAOFac
 
     public DAOFactory(final DatabaseConfigurationContext context,
             final SessionFactory sessionFactory, HibernateSearchContext hibernateSearchContext,
-            final IFullTextIndexUpdateScheduler fullTextIndexUpdateScheduler)
+            final IFullTextIndexUpdateScheduler fullTextIndexUpdateScheduler,
+            final IDynamicPropertyEvaluationScheduler dynamicPropertyEvaluationScheduler)
     {
-        super(context, sessionFactory, fullTextIndexUpdateScheduler);
+        super(context, sessionFactory, fullTextIndexUpdateScheduler,
+                dynamicPropertyEvaluationScheduler);
+        this.dynamicPropertyEvaluationScheduler = dynamicPropertyEvaluationScheduler;
         final DatabaseInstancePE databaseInstance = getHomeDatabaseInstance();
         sampleTypeDAO = new SampleTypeDAO(sessionFactory, databaseInstance);
         hibernateSearchDAO = new HibernateSearchDAO(sessionFactory, hibernateSearchContext);
@@ -223,4 +229,9 @@ public final class DAOFactory extends AuthorizationDAOFactory implements IDAOFac
         return scriptDAO;
     }
 
+    public IDynamicPropertyEvaluationScheduler getDynamicPropertyEvaluationScheduler()
+    {
+        return dynamicPropertyEvaluationScheduler;
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
index 0d91e91142526a7aabf1368715b418b26c27ee5a..aabc425c42d296f06ab71e5e71db2ddbe459eab7 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
@@ -40,6 +41,8 @@ import org.springframework.orm.hibernate3.HibernateTemplate;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.DynamicPropertyEvaluationOperation;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.IDynamicPropertyEvaluationScheduler;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
@@ -73,11 +76,15 @@ public class SampleDAO extends AbstractGenericEntityDAO<SamplePE> implements ISa
 
     private final IFullTextIndexUpdateScheduler fullTextIndexUpdateScheduler;
 
+    private final IDynamicPropertyEvaluationScheduler dynamicPropertyEvaluationScheduler;
+
     SampleDAO(final SessionFactory sessionFactory, final DatabaseInstancePE databaseInstance,
-            final IFullTextIndexUpdateScheduler fullTextIndexUpdateScheduler)
+            final IFullTextIndexUpdateScheduler fullTextIndexUpdateScheduler,
+            final IDynamicPropertyEvaluationScheduler dynamicPropertyEvaluationScheduler)
     {
         super(sessionFactory, databaseInstance, SamplePE.class);
         this.fullTextIndexUpdateScheduler = fullTextIndexUpdateScheduler;
+        this.dynamicPropertyEvaluationScheduler = dynamicPropertyEvaluationScheduler;
     }
 
     // LockSampleModificationsInterceptor automatically obtains lock
@@ -109,6 +116,7 @@ public class SampleDAO extends AbstractGenericEntityDAO<SamplePE> implements ISa
                 new ClassValidator<SamplePE>(SamplePE.class), true);
 
         flushWithSqlExceptionHandling(hibernateTemplate);
+        scheduleDynamicPropertiesEvaluation(Arrays.asList(sample));
     }
 
     public final List<SamplePE> listSamplesByGeneratedFrom(final SamplePE sample)
@@ -304,6 +312,7 @@ public class SampleDAO extends AbstractGenericEntityDAO<SamplePE> implements ISa
 
         // need to deal with exception thrown by trigger checking code uniqueness
         flushWithSqlExceptionHandling(getHibernateTemplate());
+        scheduleDynamicPropertiesEvaluation(samples);
 
         // if session is not cleared registration of many samples slows down after each batch
         hibernateTemplate.clear();
@@ -316,6 +325,7 @@ public class SampleDAO extends AbstractGenericEntityDAO<SamplePE> implements ISa
 
         // need to deal with exception thrown by trigger checking code uniqueness
         flushWithSqlExceptionHandling(getHibernateTemplate());
+        scheduleDynamicPropertiesEvaluation(Arrays.asList(sample));
 
         if (operationLog.isInfoEnabled())
         {
@@ -410,6 +420,17 @@ public class SampleDAO extends AbstractGenericEntityDAO<SamplePE> implements ISa
                 .remove(SamplePE.class, ids));
     }
 
+    private void scheduleDynamicPropertiesEvaluation(List<SamplePE> samples)
+    {
+        List<Long> sampleIds = new ArrayList<Long>();
+        for (SamplePE sample : samples)
+        {
+            sampleIds.add(sample.getId());
+        }
+        dynamicPropertyEvaluationScheduler.scheduleUpdate(DynamicPropertyEvaluationOperation
+                .evaluate(SamplePE.class, sampleIds));
+    }
+
     @SuppressWarnings("unchecked")
     // TODO 2010-07-22, IA: Merge with ExternalDataDAO after data set relationships migration
     public Set<TechId> listParents(final Collection<TechId> children, final TechId relationship)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DefaultDynamicPropertyEvaluator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DefaultDynamicPropertyEvaluator.java
new file mode 100644
index 0000000000000000000000000000000000000000..30ab7f49a0a1cc22f394e4a2aed9f5c635ffc67f
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DefaultDynamicPropertyEvaluator.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2008 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.db.dynamic_property;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.hibernate.Criteria;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Projections;
+import org.hibernate.criterion.Restrictions;
+import org.springframework.dao.DataAccessException;
+
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.openbis.generic.client.web.server.calculator.DynamicPropertyCalculator;
+import ch.systemsx.cisd.openbis.generic.client.web.server.calculator.property.EntityAdaptorFactory;
+import ch.systemsx.cisd.openbis.generic.client.web.server.calculator.property.IEntityAdaptor;
+import ch.systemsx.cisd.openbis.generic.server.util.IPropertyValueValidator;
+import ch.systemsx.cisd.openbis.generic.server.util.PropertyValidator;
+import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
+import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePropertyTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder;
+
+/**
+ * A default {@link IDynamicPropertyEvaluator}.
+ * 
+ * @author Piotr Buczek
+ */
+final class DefaultDynamicPropertyEvaluator implements IDynamicPropertyEvaluator
+{
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            DefaultDynamicPropertyEvaluator.class);
+
+    private static IPropertyValueValidator validator = new PropertyValidator();
+
+    private static String ID_PROPERTY_NAME = "id";
+
+    private final int batchSize;
+
+    DefaultDynamicPropertyEvaluator(final int batchSize)
+    {
+        assert batchSize > -1 : "Batch size can not be negative.";
+        this.batchSize = batchSize;
+    }
+
+    //
+    // IFullTextIndexer
+    //
+
+    public final <T extends IEntityInformationWithPropertiesHolder> void doEvaluateProperties(
+            final Session hibernateSession, final Class<T> clazz) throws DataAccessException
+    {
+        operationLog.debug(String.format("Evaluating dynamic properties for '%s'...",
+                clazz.getSimpleName()));
+
+        // we evaluate properties of entities in batches loading them in groups restricted by id:
+        // [ ids[index], ids[min(index+batchSize, maxIndex))] )
+        final Transaction transaction = hibernateSession.beginTransaction();
+        int index = 0;
+        final List<Long> ids = getAllIds(hibernateSession, clazz);
+        final int idsSize = ids.size();
+        operationLog.debug(String.format("... got %d '%s' ids...", idsSize, clazz.getSimpleName()));
+        final int maxIndex = idsSize - 1;
+        // need to increment last id because we use 'lt' condition
+        if (maxIndex > -1)
+        {
+            ids.set(maxIndex, ids.get(maxIndex) + 1);
+        }
+        while (index < maxIndex)
+        {
+            final int nextIndex = getNextIndex(index, maxIndex);
+            final long minId = ids.get(index);
+            final long maxId = ids.get(nextIndex);
+            final List<T> results =
+                    listEntitiesWithRestrictedId(hibernateSession, clazz, minId, maxId);
+            evaluateProperties(hibernateSession, results, clazz);
+            index = nextIndex;
+            operationLog.debug(String.format("%d/%d %ss have been updated...", index, maxIndex,
+                    clazz.getSimpleName()));
+        }
+        operationLog.debug(String.format("Evaluation of dynamic properties for '%s' is complete. "
+                + "%d entities have been updated.", clazz.getSimpleName(), index));
+        transaction.commit();
+    }
+
+    public <T extends IEntityInformationWithPropertiesHolder> void doEvaluateProperties(
+            final Session hibernateSession, final Class<T> clazz, final List<Long> ids)
+            throws DataAccessException
+    {
+        operationLog.debug(String.format("Evaluating dynamic properties for %s %ss...", ids.size(),
+                clazz.getSimpleName()));
+
+        // we index entities in batches loading them in groups by id
+        final Transaction transaction = hibernateSession.beginTransaction();
+        final int maxIndex = ids.size();
+        int index = 0;
+
+        while (index < maxIndex)
+        {
+            final int nextIndex = getNextIndex(index, maxIndex);
+            List<Long> subList = ids.subList(index, nextIndex);
+            final List<T> results = listEntitiesWithRestrictedId(hibernateSession, clazz, subList);
+            evaluateProperties(hibernateSession, results, clazz);
+            index = nextIndex;
+            if (operationLog.isDebugEnabled())
+            {
+                operationLog.debug(String.format("%d/%d %ss have been updated...", index, maxIndex,
+                        clazz.getSimpleName()));
+            }
+        }
+        transaction.commit();
+        operationLog.debug(String.format("Evaluation of dynamic properties for '%s' is complete. "
+                + "%d entities have been updated.", clazz.getSimpleName(), index));
+    }
+
+    private int getNextIndex(int index, int maxIndex)
+    {
+        return Math.min(index + batchSize, maxIndex);
+    }
+
+    private static final <T extends IEntityInformationWithPropertiesHolder> void evaluateProperties(
+            final Session session, final List<T> entities, final Class<T> clazz)
+    {
+        for (T entity : entities)
+        {
+            evaluateProperties(session, entity);
+        }
+        session.flush();
+        session.clear();
+    }
+
+    private static final <T> List<Long> getAllIds(final Session session, final Class<T> clazz)
+    {
+        Criteria criteria =
+                createCriteria(session, clazz)
+                        .setProjection(Projections.property(ID_PROPERTY_NAME)).addOrder(
+                                Order.asc(ID_PROPERTY_NAME));
+        return list(criteria);
+    }
+
+    private static final <T> List<T> listEntitiesWithRestrictedId(final Session session,
+            final Class<T> clazz, final long minId, final long maxId)
+    {
+        Criteria criteria =
+                createCriteria(session, clazz).add(Restrictions.ge(ID_PROPERTY_NAME, minId)).add(
+                        Restrictions.lt(ID_PROPERTY_NAME, maxId));
+        return list(criteria);
+
+    }
+
+    private static final <T> List<T> listEntitiesWithRestrictedId(final Session hibernateSession,
+            final Class<T> clazz, final List<Long> ids)
+    {
+        Criteria criteria =
+                createCriteria(hibernateSession, clazz).add(Restrictions.in(ID_PROPERTY_NAME, ids));
+        return list(criteria);
+
+    }
+
+    private static final <T> Criteria createCriteria(final Session session, final Class<T> clazz)
+    {
+        return session.createCriteria(clazz);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static final <T> List<T> list(final Criteria criteria)
+    {
+        return criteria.list();
+    }
+
+    private static final <T extends IEntityInformationWithPropertiesHolder> void evaluateProperties(
+            final Session session, T entity)
+    {
+        if (operationLog.isDebugEnabled())
+        {
+            operationLog.debug(String.format("Evaluating dynamic properties of entity '%s'.",
+                    entity));
+        }
+        for (EntityPropertyPE property : entity.getProperties())
+        {
+            EntityTypePropertyTypePE etpt = property.getEntityTypePropertyType();
+            if (etpt.isDynamic())
+            {
+                try
+                {
+                    DynamicPropertyCalculator calculator =
+                            new DynamicPropertyCalculator(etpt.getScript().getScript());
+                    final IEntityAdaptor entityAdaptor = EntityAdaptorFactory.create(entity);
+                    calculator.setEntity(entityAdaptor);
+                    final String dynamicValue = calculator.evalAsString();
+                    final String validatedValue =
+                            validator.validatePropertyValue(etpt.getPropertyType(), dynamicValue);
+                    property.setValue(validatedValue);
+                } catch (Exception e)
+                {
+                    String errorMsg = "ERROR: " + e.getMessage();
+                    operationLog.info(errorMsg);
+                    property.setValue(BasicConstant.ERROR_PROPERTY_PREFIX + errorMsg);
+                }
+            }
+        }
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DynamicPropertyEvaluationOperation.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DynamicPropertyEvaluationOperation.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6a9dd8dcb2cc1ecf985be7e164dc37c99614d81
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DynamicPropertyEvaluationOperation.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 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.db.dynamic_property;
+
+import java.io.Serializable;
+import java.util.List;
+
+import ch.systemsx.cisd.common.collections.CollectionUtils;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder;
+
+/**
+ * Encapsulates operation kind and data for an update operation.
+ * 
+ * @author Piotr Buczek
+ */
+public class DynamicPropertyEvaluationOperation implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    // we don't store Class<?> not to cause problems with deserialization
+    private final String className;
+
+    // null means all
+    private final List<Long> ids;
+
+    public static DynamicPropertyEvaluationOperation evaluate(
+            Class<? extends IEntityInformationWithPropertiesHolder> clazz, List<Long> ids)
+    {
+        return new DynamicPropertyEvaluationOperation(clazz, ids);
+    }
+
+    public static DynamicPropertyEvaluationOperation evaluateAll(
+            Class<? extends IEntityInformationWithPropertiesHolder> clazz)
+    {
+        return new DynamicPropertyEvaluationOperation(clazz, null);
+    }
+
+    private DynamicPropertyEvaluationOperation(
+            Class<? extends IEntityInformationWithPropertiesHolder> clazz, List<Long> ids)
+    {
+        this.className = clazz.getName();
+        this.ids = ids;
+    }
+
+    public String getClassName()
+    {
+        return className;
+    }
+
+    public List<Long> getIds()
+    {
+        return ids;
+    }
+
+    @Override
+    public String toString()
+    {
+        return className + ": " + (ids == null ? "all" : CollectionUtils.abbreviate(ids, 10));
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DynamicPropertyEvaluationRunnable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DynamicPropertyEvaluationRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..da54c003df6d4d6c04cf287ef403c6e121f4abfa
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/DynamicPropertyEvaluationRunnable.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2008 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.db.dynamic_property;
+
+import java.io.File;
+
+import org.apache.commons.lang.time.StopWatch;
+import org.apache.log4j.Logger;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
+
+import ch.systemsx.cisd.common.collections.ExtendedBlockingQueueFactory;
+import ch.systemsx.cisd.common.collections.IExtendedBlockingQueue;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder;
+
+/**
+ * @author Piotr Buczek
+ */
+public final class DynamicPropertyEvaluationRunnable extends HibernateDaoSupport implements
+        IDynamicPropertyEvaluationScheduler, Runnable
+{
+    private static final int BATCH_SIZE = 1000;
+
+    public final static String DYNAMIC_PROPERTY_EVALUATOR_QUEUE_FILENAME =
+            ".dynamic_property_evaluator_queue";
+
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            DynamicPropertyEvaluationRunnable.class);
+
+    private static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY,
+            DynamicPropertyEvaluationRunnable.class);
+
+    private final IDynamicPropertyEvaluator evaluator;
+
+    private final IExtendedBlockingQueue<DynamicPropertyEvaluationOperation> evaluatorQueue;
+
+    public DynamicPropertyEvaluationRunnable(final SessionFactory sessionFactory)
+    {
+        setSessionFactory(sessionFactory);
+        evaluator = new DefaultDynamicPropertyEvaluator(BATCH_SIZE);
+
+        final File queueFile = getEvaluatorQueueFile();
+        operationLog.info(String.format("Evaluator queue file: %s.", queueFile.getAbsolutePath()));
+        evaluatorQueue = createEvaluatorQueue(queueFile);
+    }
+
+    private static IExtendedBlockingQueue<DynamicPropertyEvaluationOperation> createEvaluatorQueue(
+            final File queueFile)
+    {
+        try
+        {
+            return ExtendedBlockingQueueFactory
+                    .<DynamicPropertyEvaluationOperation> createPersistRecordBased(queueFile);
+        } catch (RuntimeException e)
+        {
+            // don't fail if e.g. deserialization of the queue fails (see SE-286)
+            String newFileName =
+                    DYNAMIC_PROPERTY_EVALUATOR_QUEUE_FILENAME + "_" + System.currentTimeMillis();
+            notificationLog.error(String.format("%s.\n "
+                    + "Renaming '%s' to '%s' and using an empty queue file. "
+                    + "Restart server with the queue that caused the problem or "
+                    + "wait for maintenance task to reevaluate all properties.", e.getMessage(),
+                    queueFile, newFileName));
+            queueFile.renameTo(new File(newFileName));
+            return ExtendedBlockingQueueFactory
+                    .<DynamicPropertyEvaluationOperation> createPersistRecordBased(queueFile);
+        }
+    }
+
+    private static File getEvaluatorQueueFile()
+    {
+        return new File(DYNAMIC_PROPERTY_EVALUATOR_QUEUE_FILENAME);
+    }
+
+    public void clear()
+    {
+        evaluatorQueue.clear();
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info("Cleared evaluator queue.");
+        }
+    }
+
+    public void scheduleUpdate(DynamicPropertyEvaluationOperation operation)
+    {
+        if (operationLog.isDebugEnabled())
+        {
+            operationLog.debug("Scheduling update: " + operation);
+        }
+        evaluatorQueue.add(operation);
+    }
+
+    //
+    // Runnable
+    //
+
+    @SuppressWarnings("unchecked")
+    public final void run()
+    {
+        try
+        {
+            while (true)
+            {
+                final DynamicPropertyEvaluationOperation operation = evaluatorQueue.peekWait();
+                if (operationLog.isInfoEnabled())
+                {
+                    operationLog.info("Update: " + operation);
+                }
+                final StopWatch stopWatch = new StopWatch();
+                stopWatch.start();
+                Session session = null;
+                try
+                {
+                    final Class<IEntityInformationWithPropertiesHolder> clazz =
+                            (Class<IEntityInformationWithPropertiesHolder>) Class.forName(operation
+                                    .getClassName());
+                    session = getSession();
+                    if (operation.getIds() == null)
+                    {
+                        evaluator.doEvaluateProperties(getSession(), clazz);
+                    } else
+                    {
+                        evaluator.doEvaluateProperties(getSession(), clazz, operation.getIds());
+                    }
+                    stopWatch.stop();
+                } catch (RuntimeException e)
+                {
+                    notificationLog.error("Error: " + operation + ".", e);
+                } finally
+                {
+                    if (session != null)
+                    {
+                        releaseSession(session);
+                    }
+                    if (operationLog.isInfoEnabled())
+                    {
+                        operationLog.info("Update of "
+                                + (operation.getIds() == null ? "" : operation.getIds().size()
+                                        + " ") + operation.getClassName() + "s took " + stopWatch);
+                    }
+                }
+                evaluatorQueue.take();
+            }
+        } catch (final Throwable th)
+        {
+            notificationLog
+                    .error("A problem has occurred while evaluating dynamic properties.", th);
+        }
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/IDynamicPropertyEvaluationScheduler.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/IDynamicPropertyEvaluationScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..8722cb71009a400c84a630b78543f177053bfb11
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/IDynamicPropertyEvaluationScheduler.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2008 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.db.dynamic_property;
+
+/**
+ * @author Piotr Buczek
+ */
+public interface IDynamicPropertyEvaluationScheduler
+{
+    /**
+     * Schedules specified operation.
+     */
+    void scheduleUpdate(DynamicPropertyEvaluationOperation operation);
+
+    /**
+     * Clears the schedule.
+     */
+    void clear();
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/IDynamicPropertyEvaluator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/IDynamicPropertyEvaluator.java
new file mode 100644
index 0000000000000000000000000000000000000000..72b7e48184e33af2417100ae7d2e590a1a168e84
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/IDynamicPropertyEvaluator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008 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.db.dynamic_property;
+
+import java.util.List;
+
+import org.hibernate.Session;
+import org.springframework.dao.DataAccessException;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder;
+
+/**
+ * Each implementation is able to evaluate dynamic properties.
+ * 
+ * @author Piotr Buczek
+ */
+public interface IDynamicPropertyEvaluator
+{
+
+    /**
+     * Evaluates dynamic properties of all entities of given <var>clazz</var> using given
+     * <i>Hibernate</i> session.
+     */
+    public <T extends IEntityInformationWithPropertiesHolder> void doEvaluateProperties(
+            final Session hibernateSession, final Class<T> clazz) throws DataAccessException;
+
+    /**
+     * Evaluates dynamic properties of entities of given <var>clazz</var> with given <var>ids</var>
+     * using given <i>Hibernate</i> session.
+     */
+    public <T extends IEntityInformationWithPropertiesHolder> void doEvaluateProperties(
+            final Session hibernateSession, final Class<T> clazz, final List<Long> ids)
+            throws DataAccessException;
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java
index ab0b9ed4389f1b0385f187a27379b9e0214bc697..88afe66ffc87c67448878d482e4317b004218d31 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/DefaultFullTextIndexer.java
@@ -45,8 +45,8 @@ import ch.systemsx.cisd.common.logging.LogFactory;
  */
 final class DefaultFullTextIndexer implements IFullTextIndexer
 {
-    private static final Logger operationLog =
-            LogFactory.getLogger(LogCategory.OPERATION, DefaultFullTextIndexer.class);
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            DefaultFullTextIndexer.class);
 
     private static String ID_PROPERTY_NAME = "id";
 
@@ -97,8 +97,8 @@ final class DefaultFullTextIndexer implements IFullTextIndexer
                     listEntitiesWithRestrictedId(fullTextSession, clazz, minId, maxId);
             indexEntities(fullTextSession, results, clazz);
             index = nextIndex;
-            operationLog.info(String.format("%d %ss have been indexed...", index, clazz
-                    .getSimpleName()));
+            operationLog.info(String.format("%d/%d %ss have been indexed...", index, maxIndex,
+                    clazz.getSimpleName()));
         }
         fullTextSession.getSearchFactory().optimize(clazz);
         operationLog.info(String.format("'%s' index complete. %d entities have been indexed.",
@@ -124,8 +124,8 @@ final class DefaultFullTextIndexer implements IFullTextIndexer
             final List<T> results = listEntitiesWithRestrictedId(fullTextSession, clazz, subList);
             indexEntities(fullTextSession, results, clazz);
             index = nextIndex;
-            operationLog.info(String.format("%d %ss have been reindexed...", index, clazz
-                    .getSimpleName()));
+            operationLog.info(String.format("%d/%d %ss have been reindexed...", index, maxIndex,
+                    clazz.getSimpleName()));
         }
         fullTextSession.getSearchFactory().optimize(clazz);
         transaction.commit();
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/DynamicPropertyEvaluationMaintenanceTask.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/DynamicPropertyEvaluationMaintenanceTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..417a9e0c499d59795a9a41125adb09089f821d77
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/DynamicPropertyEvaluationMaintenanceTask.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010 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.task;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.maintenance.IMaintenanceTask;
+import ch.systemsx.cisd.openbis.generic.server.CommonServiceProvider;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.DynamicPropertyEvaluationOperation;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.IDynamicPropertyEvaluationScheduler;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityInformationWithPropertiesHolder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+
+/**
+ * {@link IMaintenanceTask} for reevaluation of all dynamic properties.
+ * 
+ * @author Piotr Buczek
+ */
+public class DynamicPropertyEvaluationMaintenanceTask implements IMaintenanceTask
+{
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            DynamicPropertyEvaluationMaintenanceTask.class);
+
+    private static final List<Class<? extends IEntityInformationWithPropertiesHolder>> entityClasses =
+            new ArrayList<Class<? extends IEntityInformationWithPropertiesHolder>>();
+
+    static
+    {
+        entityClasses.add(ExternalDataPE.class);
+        entityClasses.add(ExperimentPE.class);
+        entityClasses.add(MaterialPE.class);
+        entityClasses.add(SamplePE.class);
+    }
+
+    public void execute()
+    {
+        operationLog.info("execution started");
+        IDynamicPropertyEvaluationScheduler scheduler =
+                CommonServiceProvider.getDAOFactory().getDynamicPropertyEvaluationScheduler();
+
+        // all entities will be scheduled for update so previous schedule can be cleared
+        scheduler.clear();
+        for (Class<? extends IEntityInformationWithPropertiesHolder> entityClass : entityClasses)
+        {
+            DynamicPropertyEvaluationOperation operation =
+                    DynamicPropertyEvaluationOperation.evaluateAll(entityClass);
+            scheduler.scheduleUpdate(operation);
+        }
+        operationLog.info("task executed");
+    }
+
+    public void setUp(String pluginName, Properties properties)
+    {
+        operationLog.info("Task " + pluginName + " initialized.");
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/PropertyValidator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/PropertyValidator.java
index fb8cd45510f8e4c3604e1c1a552f7d8bc1d8910f..9e412803d794bafdb79bb861b325d7cda383608b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/PropertyValidator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/util/PropertyValidator.java
@@ -115,6 +115,11 @@ public final class PropertyValidator implements IPropertyValueValidator
         return datePatterns.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
     }
 
+    public PropertyValidator()
+    {
+        // NOTE: controlled vocabulary validator will always fail
+    }
+
     public PropertyValidator(IDAOFactory daoFactory)
     {
         assert daoFactory != null : "Unspecified DAO factory.";
@@ -303,6 +308,12 @@ public final class PropertyValidator implements IPropertyValueValidator
             assert value != null : "Unspecified value.";
             assert vocabulary != null : "Unspecified vocabulary.";
 
+            if (daoFactory == null)
+            {
+                throw UserFailureException
+                        .fromTemplate("Controlled vocabulary validator wasn't initialized.");
+            }
+
             final String upperCaseValue = value.toUpperCase();
             VocabularyTermPE termOrNull =
                     daoFactory.getVocabularyDAO().tryFindVocabularyTermByCode(vocabulary,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataPE.java
index 71a0c5d35ded054a14c2ada40688c953a604e9f1..baaae5390966a9a91e1306cd58b2f2fbd2399025 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataPE.java
@@ -78,8 +78,8 @@ import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
 @Table(name = TableNames.DATA_TABLE, uniqueConstraints = @UniqueConstraint(columnNames = ColumnNames.CODE_COLUMN))
 @Inheritance(strategy = InheritanceType.JOINED)
 @Friend(toClasses = EventPE.class)
-public class DataPE extends AbstractIdAndCodeHolder<DataPE> implements IEntityPropertiesHolder,
-        IEntityInformationHolderDTO, IIdentifierHolder, ICodeHolder
+public class DataPE extends AbstractIdAndCodeHolder<DataPE> implements
+        IEntityInformationWithPropertiesHolder, IIdentifierHolder, ICodeHolder
 {
     private static final long serialVersionUID = IServer.VERSION;
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java
index f515ba276e4bcadfd8154b260cf2d2a71c4f30d6..5c7b7881e6d9b9e78acad5617da9e430442c417d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java
@@ -85,8 +85,9 @@ import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
 @Indexed
 @Friend(toClasses =
     { AttachmentPE.class, ProjectPE.class })
-public class ExperimentPE extends AttachmentHolderPE implements IEntityPropertiesHolder,
-        IIdAndCodeHolder, Comparable<ExperimentPE>, IMatchingEntity, Serializable
+public class ExperimentPE extends AttachmentHolderPE implements
+        IEntityInformationWithPropertiesHolder, IIdAndCodeHolder, Comparable<ExperimentPE>,
+        IMatchingEntity, Serializable
 {
     private static final long serialVersionUID = IServer.VERSION;
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/IEntityInformationWithPropertiesHolder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/IEntityInformationWithPropertiesHolder.java
new file mode 100644
index 0000000000000000000000000000000000000000..0494c6a7a2c1a159b7e7a7537d48bde2eddbe2c7
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/IEntityInformationWithPropertiesHolder.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 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.shared.dto;
+
+
+/**
+ * @author Piotr Buczek
+ */
+public interface IEntityInformationWithPropertiesHolder extends IEntityInformationHolderDTO,
+        IEntityPropertiesHolder
+{
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/MaterialPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/MaterialPE.java
index 3d30ec250a5383003f25356eae01647894c8cdc8..4e5fb53d490db6b9fffd094444d881e49dfd53b3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/MaterialPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/MaterialPE.java
@@ -76,7 +76,7 @@ import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
             ColumnNames.DATABASE_INSTANCE_COLUMN }))
 @Indexed
 public class MaterialPE implements IIdAndCodeHolder, Comparable<MaterialPE>,
-        IEntityPropertiesHolder, Serializable, IMatchingEntity
+        IEntityInformationWithPropertiesHolder, Serializable, IMatchingEntity
 {
     private static final long serialVersionUID = IServer.VERSION;
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java
index 4cf3daa262931068039f5312a178091d7e794aef..2c5f8a6a7337bd7060c7c3b065f415d1fc2329b2 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java
@@ -86,7 +86,7 @@ import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
         + " IS NULL AND " + ColumnNames.GROUP_COLUMN + " IS NOT NULL)")
 @Indexed
 public class SamplePE extends AttachmentHolderPE implements IIdAndCodeHolder, Comparable<SamplePE>,
-        IEntityPropertiesHolder, IMatchingEntity, Serializable
+        IEntityInformationWithPropertiesHolder, IMatchingEntity, Serializable
 {
     private static final long serialVersionUID = IServer.VERSION;
 
diff --git a/openbis/source/java/genericApplicationContext.xml b/openbis/source/java/genericApplicationContext.xml
index 159ce4c71faf548afcbb530e28c796189d25d1ce..430be2ce64c20adc5708fbd51dc910ea9be86c45 100644
--- a/openbis/source/java/genericApplicationContext.xml
+++ b/openbis/source/java/genericApplicationContext.xml
@@ -37,6 +37,7 @@
         <constructor-arg ref="hibernate-session-factory" />
         <constructor-arg ref="hibernate-search-context" />
         <constructor-arg ref="full-text-index-updater" />
+        <constructor-arg ref="dynamic-property-evaluator" />
     </bean>
     
     <bean id="dss-factory" class="ch.systemsx.cisd.openbis.generic.server.business.DataStoreServiceFactory"/>
diff --git a/openbis/source/java/hibernateContext.xml b/openbis/source/java/hibernateContext.xml
index 163485d773e14ade9637e220e8e6db64621a3fe6..cf45f10d8182a5ca3375afac8fa066a5c2d98545 100644
--- a/openbis/source/java/hibernateContext.xml
+++ b/openbis/source/java/hibernateContext.xml
@@ -153,6 +153,11 @@
         <constructor-arg ref="hibernate-search-context" />
         <constructor-arg ref="full-text-index-updater" />
     </bean>
+
+    <bean id="dynamic-property-evaluator"
+        class="ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.DynamicPropertyEvaluationRunnable">
+        <constructor-arg ref="hibernate-session-factory" />
+    </bean>
     
     <bean id="maintenance-task-starter" 
         class="ch.systemsx.cisd.openbis.generic.server.MaintenanceTaskStarterRunnable">
@@ -165,6 +170,10 @@
                     <property name="delay" value="0" />
                     <property name="runnable" ref="full-text-indexer" />
                 </bean>
+                <bean class="org.springframework.scheduling.timer.ScheduledTimerTask">
+                    <property name="delay" value="0" />
+                    <property name="runnable" ref="dynamic-property-evaluator" />
+                </bean>
                 <bean class="org.springframework.scheduling.timer.ScheduledTimerTask">
                     <property name="delay" value="0" />
                     <property name="runnable" ref="maintenance-task-starter" />
diff --git a/openbis/source/java/service.properties b/openbis/source/java/service.properties
index 2ab3af311549cd6a7a4180e54c89389c2d77c9a5..59259c793df00e4cd769a4b472c4d56495efb69e 100644
--- a/openbis/source/java/service.properties
+++ b/openbis/source/java/service.properties
@@ -116,7 +116,7 @@ query-databases = 1
 #   <plugin>.start - Time of the first execution (HH:mm)
 #   <plugin>.execute-only-once - If true the task will be executed exactly once, 
 #                                interval will be ignored. By default set to false.
-#maintenance-plugins = demo
+#maintenance-plugins = demo, dynamic-property-evaluator
 
 demo.class = ch.systemsx.cisd.openbis.generic.server.task.DemoMaintenanceTask
 demo.interval = 60
@@ -124,5 +124,12 @@ demo.interval = 60
 demo.property_1 = some value
 demo.property_2 = some value 2
 
+#dynamic-property-evaluator.class = ch.systemsx.cisd.openbis.generic.server.task.DynamicPropertyEvaluationMaintenanceTask
+# run daily at midnight  
+#dynamic-property-evaluator.interval = 86400
+#dynamic-property-evaluator.start = 00:00
+# run every 10min
+#dynamic-property-evaluator.interval = 6000
+
 # Name of the file that stores Web Client configuration
 web-client-configuration-file = etc/web-client.properties