diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java index b73ca486c10a5a66ffd9ba052bfec3db81bc78f5..738ee3c13347c2a6a6d9d2e223340eb4ca3c21b0 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java @@ -723,6 +723,7 @@ public class DatasetLister extends AbstractLister implements IDatasetLister dataSet.setProductionDate(record.production_timestamp); dataSet.setRegistrationDate(record.registration_timestamp); dataSet.setRegistrator(getOrCreateRegistrator(record.pers_id_registerer)); + dataSet.setModificationDate(record.modification_timestamp); dataSet.setDataSetProperties(new ArrayList<IEntityProperty>()); if (record.ctnr_id != null) diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetRecord.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetRecord.java index 7477f825affc64212812dc215008b62ceb70d618..542fa8937811c087b55d19452d83e2d2cb62d7ab 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetRecord.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetRecord.java @@ -27,6 +27,8 @@ public class DatasetRecord extends CodeRecord public Date registration_timestamp; + public Date modification_timestamp; + public Long pers_id_registerer; public boolean is_placeholder; diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/builders/DataSetBuilder.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/builders/DataSetBuilder.java index 14ed412a2c3bd2a5b415640518f186cc5f3a28d5..195caac5945a6824e6281ff28fe6423b14984543 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/builders/DataSetBuilder.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/builders/DataSetBuilder.java @@ -27,6 +27,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStore; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; @@ -93,6 +94,12 @@ public class DataSetBuilder return this; } + public DataSetBuilder fileFormat(String fileFormatType) + { + dataSet.setFileFormatType(new FileFormatType(fileFormatType)); + return this; + } + public DataSetBuilder status(DataSetArchivingStatus status) { dataSet.setStatus(status); diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForProteinResults.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForProteinResults.java index 95564639f7965361844615f46b2babb39316386b..b68ab4c4b2bcf5cc7fd9d9840260d7ceafde9cc5 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForProteinResults.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForProteinResults.java @@ -100,31 +100,46 @@ public class DataSetInfoExtractorForProteinResults extends AbstractDataSetInfoEx DataSetInformation info = new DataSetInformation(); info.setExperimentIdentifier(experimentIdentifier); String parentDataSetCodesOrNull = getProperty(properties, PARENT_DATA_SET_CODES); + String baseExperimentIdentifier = getProperty(properties, EXPERIMENT_IDENTIFIER_KEY); + List<String> parentDataSetCodes = + getParentDataSetCodes(parentDataSetCodesOrNull, baseExperimentIdentifier, service); + info.setParentDataSetCodes(parentDataSetCodes); + return info; + } + + /** + * Returns data set codes either from the first argument or if <code>null</code> from + * the data sets of the specified experiment. + */ + static List<String> getParentDataSetCodes(String parentDataSetCodesOrNull, + String baseExperimentIdentifier, IEncapsulatedOpenBISService service) + { + List<String> parentDataSetCodes = new ArrayList<String>(); if (parentDataSetCodesOrNull != null) { - info.setParentDataSetCodes(Arrays.asList(StringUtils.split(parentDataSetCodesOrNull, ", "))); - } else + parentDataSetCodes = Arrays.asList(StringUtils.split(parentDataSetCodesOrNull, ", ")); + } else { - String baseExperimentIdentifier = getProperty(properties, EXPERIMENT_IDENTIFIER_KEY); if (baseExperimentIdentifier != null) { - ExperimentIdentifier identifier = new ExperimentIdentifierFactory(baseExperimentIdentifier).createIdentifier(); + ExperimentIdentifier identifier = + new ExperimentIdentifierFactory(baseExperimentIdentifier) + .createIdentifier(); Experiment baseExperiment = service.tryToGetExperiment(identifier); if (baseExperiment == null) { throw new UserFailureException("Property " + EXPERIMENT_IDENTIFIER_KEY + " specifies an unknown experiment: " + baseExperimentIdentifier); } - List<ExternalData> dataSets = service.listDataSetsByExperimentID(baseExperiment.getId()); - List<String> parentDataSetCodes = new ArrayList<String>(); + List<ExternalData> dataSets = + service.listDataSetsByExperimentID(baseExperiment.getId()); for (ExternalData dataSet : dataSets) { parentDataSetCodes.add(dataSet.getCode()); } - info.setParentDataSetCodes(parentDataSetCodes); } } - return info; + return parentDataSetCodes; } private String getProperty(Properties properties, String key) diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ProteinResultDataSetParentLinkingTask.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ProteinResultDataSetParentLinkingTask.java new file mode 100644 index 0000000000000000000000000000000000000000..1c33685a0764e097481af8644dc520708811acb7 --- /dev/null +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ProteinResultDataSetParentLinkingTask.java @@ -0,0 +1,175 @@ +/* + * Copyright 2011 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.etlserver.phosphonetx; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Pattern; + +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.dss.generic.shared.IEncapsulatedOpenBISService; +import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; +import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSet; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewMaterial; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewProject; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSpace; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project; +import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails; +import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUpdatesDTO; +import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; +import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier; + +/** + * @author Franz-Josef Elmer + */ +public class ProteinResultDataSetParentLinkingTask implements IMaintenanceTask +{ + private static final Pattern DATA_SET_CODE_PATTERN = Pattern.compile("\\d{17}-\\d+"); + + private static final String PARENT_DATA_SET_CODES_KEY = + DataSetInfoExtractorForProteinResults.PARENT_DATA_SET_CODES.toUpperCase(); + + private static final String BASE_EXPERIMENT_KEY = + DataSetInfoExtractorForProteinResults.EXPERIMENT_IDENTIFIER_KEY.toUpperCase(); + + private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, + ProteinResultDataSetParentLinkingTask.class); + + private final IEncapsulatedOpenBISService service; + + public ProteinResultDataSetParentLinkingTask() + { + this(ServiceProvider.getOpenBISService()); + } + + ProteinResultDataSetParentLinkingTask(IEncapsulatedOpenBISService service) + { + this.service = service; + + } + + public void setUp(String pluginName, Properties properties) + { + } + + public void execute() + { + List<DataSetUpdatesDTO> dataSetUpdates = new ArrayList<DataSetUpdatesDTO>(); + List<Project> projects = service.listProjects(); + for (Project project : projects) + { + List<Experiment> experiments = + service.listExperiments(new ProjectIdentifier(project.getSpace().getCode(), + project.getCode())); + for (Experiment experiment : experiments) + { + Map<String, IEntityProperty> propertiesMap = getPropertiesMap(experiment); + String baseExperimentIdentifier = + tryGetProperty(propertiesMap, BASE_EXPERIMENT_KEY); + String parentDataSetCodes = + tryGetProperty(propertiesMap, PARENT_DATA_SET_CODES_KEY); + List<String> codes = + filter(DataSetInfoExtractorForProteinResults.getParentDataSetCodes( + parentDataSetCodes, baseExperimentIdentifier, service)); + if (codes.isEmpty()) + { + continue; + } + List<ExternalData> dataSets = + service.listDataSetsByExperimentID(experiment.getId()); + if (dataSets.isEmpty()) + { + continue; + } + for (ExternalData ds : dataSets) + { + if (ds instanceof DataSet == false) + { + continue; + } + DataSet dataSet = (DataSet) ds; + DataSetUpdatesDTO update = new DataSetUpdatesDTO(); + update.setDatasetId(new TechId(dataSet.getId())); + update.setVersion(dataSet.getModificationDate()); + update.setExperimentIdentifierOrNull(ExperimentIdentifierFactory.parse(dataSet + .getExperiment().getIdentifier())); + update.setModifiedParentDatasetCodesOrNull(codes.toArray(new String[0])); + update.setFileFormatTypeCode(dataSet.getFileFormatType().getCode()); + update.setProperties(dataSet.getProperties()); + operationLog.info("Parent data set links of data set " + dataSet.getCode() + + " from experiment " + experiment.getIdentifier() + + " will be updated."); + dataSetUpdates.add(update); + } + } + } + service.performEntityOperations(new AtomicEntityOperationDetails(null, Collections + .<NewSpace> emptyList(), Collections.<NewProject> emptyList(), Collections + .<NewExperiment> emptyList(), Collections.<SampleUpdatesDTO> emptyList(), + Collections.<NewSample> emptyList(), Collections + .<String, List<NewMaterial>> emptyMap(), Collections + .<NewExternalData> emptyList(), dataSetUpdates)); + operationLog.info("Parent data set links for " + dataSetUpdates.size() + + " data sets have been updated."); + } + + private Map<String, IEntityProperty> getPropertiesMap(Experiment experiment) + { + List<IEntityProperty> properties = experiment.getProperties(); + Map<String, IEntityProperty> propertiesMap = new HashMap<String, IEntityProperty>(); + for (IEntityProperty property : properties) + { + propertiesMap.put(property.getPropertyType().getCode(), property); + } + return propertiesMap; + } + + private String tryGetProperty(Map<String, IEntityProperty> propertiesMap, String key) + { + IEntityProperty property = propertiesMap.get(key); + return property == null ? null : property.tryGetAsString(); + } + + private List<String> filter(List<String> codes) + { + List<String> result = new ArrayList<String>(); + for (String code : codes) + { + if (DATA_SET_CODE_PATTERN.matcher(code).matches()) + { + result.add(code); + } + } + return result; + } +} diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ProteinResultDataSetParentLinkingTaskTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ProteinResultDataSetParentLinkingTaskTest.java new file mode 100644 index 0000000000000000000000000000000000000000..53aff1de1eb68aff9b0a59ba0a9cfec9c4b2343c --- /dev/null +++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ProteinResultDataSetParentLinkingTaskTest.java @@ -0,0 +1,174 @@ +/* + * Copyright 2011 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.etlserver.phosphonetx; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.apache.log4j.Level; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.common.logging.BufferedAppender; +import ch.systemsx.cisd.common.test.RecordingMatcher; +import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSet; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.DataSetBuilder; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ExperimentBuilder; +import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails; +import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUpdatesDTO; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier; + +/** + * @author Franz-Josef Elmer + */ +public class ProteinResultDataSetParentLinkingTaskTest extends AssertJUnit +{ + private static final String PARENT_DATA_SET_CODES_KEY = + DataSetInfoExtractorForProteinResults.PARENT_DATA_SET_CODES.toUpperCase(); + + private static final String BASE_EXPERIMENT_KEY = + DataSetInfoExtractorForProteinResults.EXPERIMENT_IDENTIFIER_KEY.toUpperCase(); + + private BufferedAppender logRecorder; + + private Mockery context; + + private IEncapsulatedOpenBISService service; + + private ProteinResultDataSetParentLinkingTask task; + + @BeforeMethod + public void beforeMethod() + { + logRecorder = new BufferedAppender("%-5p %c - %m%n", Level.DEBUG); + context = new Mockery(); + service = context.mock(IEncapsulatedOpenBISService.class); + task = new ProteinResultDataSetParentLinkingTask(service); + } + + @AfterMethod + public void afterMethod() + { + logRecorder.reset(); + // To following line of code should also be called at the end of each test method. + // Otherwise one do not known which test failed. + context.assertIsSatisfied(); + } + + @Test + public void test() + { + final Experiment e1 = + new ExperimentBuilder().id(1).identifier("/S/P1/E1").property("ABC", "non-sense") + .getExperiment(); + final Experiment e2 = + new ExperimentBuilder().id(2).identifier("/A/P2/E2") + .property(PARENT_DATA_SET_CODES_KEY, "non-sense").getExperiment(); + final Experiment e3 = + new ExperimentBuilder() + .id(3) + .identifier("/A/P2/E3") + .property(PARENT_DATA_SET_CODES_KEY, + "20100930111833087-297733, 20100511163311581-25265") + .getExperiment(); + final Experiment e4 = + new ExperimentBuilder().id(4).identifier("/S/P1/E4") + .property(BASE_EXPERIMENT_KEY, "/S/P1/E1").getExperiment(); + final DataSet ds1 = + new DataSetBuilder(1).code("20100930111811581-25265").fileFormat("A") + .experiment(e1).modificationDate(new Date(11)).getDataSet(); + final DataSet ds2 = + new DataSetBuilder(2).code("20100930111811087-29765").fileFormat("B") + .experiment(e4).modificationDate(new Date(22)).getDataSet(); + final DataSet ds3 = + new DataSetBuilder(3).code("20100530111833087-297733").fileFormat("C") + .experiment(e3).modificationDate(new Date(33)).property("ALPHA", "3.1") + .getDataSet(); + final RecordingMatcher<AtomicEntityOperationDetails> operationRecorder = + new RecordingMatcher<AtomicEntityOperationDetails>(); + context.checking(new Expectations() + { + { + one(service).listProjects(); + will(returnValue(Arrays.asList(e1.getProject(), e2.getProject()))); + + one(service).listExperiments(new ProjectIdentifier("S", "P1")); + will(returnValue(Arrays.asList(e1, e4))); + + one(service).listExperiments(new ProjectIdentifier("A", "P2")); + will(returnValue(Arrays.asList(e2, e3))); + + one(service).tryToGetExperiment(ExperimentIdentifierFactory.parse("/S/P1/E1")); + will(returnValue(e1)); + + one(service).listDataSetsByExperimentID(e1.getId()); + will(returnValue(Arrays.asList(ds1))); + + one(service).listDataSetsByExperimentID(e3.getId()); + will(returnValue(Arrays.asList(ds3))); + + one(service).listDataSetsByExperimentID(e4.getId()); + will(returnValue(Arrays.asList(ds2))); + + one(service).performEntityOperations(with(operationRecorder)); + } + }); + + task.execute(); + + assertEquals("INFO OPERATION.ProteinResultDataSetParentLinkingTask - " + + "Parent data set links of data set 20100930111811087-29765 " + + "from experiment /S/P1/E4 will be updated.\n" + + "INFO OPERATION.ProteinResultDataSetParentLinkingTask - " + + "Parent data set links of data set 20100530111833087-297733 " + + "from experiment /A/P2/E3 will be updated.\n" + + "INFO OPERATION.ProteinResultDataSetParentLinkingTask - " + + "Parent data set links for 2 data sets have been updated.", + logRecorder.getLogContent()); + List<DataSetUpdatesDTO> dataSetUpdates = + operationRecorder.recordedObject().getDataSetUpdates(); + assertEquals(2L, dataSetUpdates.get(0).getDatasetId().getId().longValue()); + assertEquals(22L, dataSetUpdates.get(0).getVersion().getTime()); + assertEquals("B", dataSetUpdates.get(0).getFileFormatTypeCode()); + assertEquals("[]", dataSetUpdates.get(0).getProperties().toString()); + assertEquals(e4.getIdentifier(), dataSetUpdates.get(0).getExperimentIdentifierOrNull() + .toString()); + assertEquals("[20100930111811581-25265]", + Arrays.asList(dataSetUpdates.get(0).getModifiedParentDatasetCodesOrNull()) + .toString()); + assertEquals(3L, dataSetUpdates.get(1).getDatasetId().getId().longValue()); + assertEquals(33L, dataSetUpdates.get(1).getVersion().getTime()); + assertEquals("C", dataSetUpdates.get(1).getFileFormatTypeCode()); + assertEquals("[ALPHA: 3.1]", dataSetUpdates.get(1).getProperties().toString()); + assertEquals(e3.getIdentifier(), dataSetUpdates.get(1).getExperimentIdentifierOrNull() + .toString()); + assertEquals("[20100930111833087-297733, 20100511163311581-25265]", + Arrays.asList(dataSetUpdates.get(1).getModifiedParentDatasetCodesOrNull()) + .toString()); + assertEquals(2, dataSetUpdates.size()); + context.assertIsSatisfied(); + } + +}