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