diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java index 608b2e2189a8e2789a66e6f4c0e56f5df0752a78..f29c570a1116509421e35c53c5a4cb4378e3407a 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java @@ -1277,6 +1277,10 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements return SampleTranslator.translate(samplePEsUpdated, session.getBaseIndexURL()); } + /** + * This method topologically sorts the data sets to be created and creates them in the necessary + * order + */ private List<ExternalData> createDataSets(Session session, AtomicEntityOperationDetails operationDetails) { @@ -1284,22 +1288,10 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements List<? extends NewExternalData> dataSetRegistrations = operationDetails.getDataSetRegistrations(); - ArrayList<NewContainerDataSet> containerRegistrations = - new ArrayList<NewContainerDataSet>(); - // In the first pass, skip container data sets - for (NewExternalData dataSet : dataSetRegistrations) - { - if (dataSet instanceof NewContainerDataSet) - { - containerRegistrations.add((NewContainerDataSet) dataSet); - } else - { - registerDatasetInternal(session, dataSetsCreated, dataSet); - } - } + NewExternalDataDAG dag = new NewExternalDataDAG(dataSetRegistrations); + List<? extends NewExternalData> orderedRegistrations = dag.getOrderedRegistrations(); - // Now do the containers - for (NewContainerDataSet dataSet : containerRegistrations) + for (NewExternalData dataSet : orderedRegistrations) { registerDatasetInternal(session, dataSetsCreated, dataSet); } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/NewExternalDataDAG.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/NewExternalDataDAG.java new file mode 100644 index 0000000000000000000000000000000000000000..c8fb41cb39b6e24323724f6aa31e49e7a24425f2 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/NewExternalDataDAG.java @@ -0,0 +1,120 @@ +/* + * 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.generic.server; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import ch.systemsx.cisd.common.collections.DAG; +import ch.systemsx.cisd.openbis.generic.shared.dto.NewContainerDataSet; +import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; + +/** + * Represents a DAG of registration dependencies between new data sets. + * + * @author Chandrasekhar Ramakrishnan + */ +public class NewExternalDataDAG +{ + private final List<? extends NewExternalData> dataSetRegistrations; + + // For simplicity, we use the data set codes to construct the graph, so we need a map from + // codes to data sets + HashMap<String, NewExternalData> codeToDataMap = new HashMap<String, NewExternalData>(); + + HashMap<String, ArrayList<String>> dependencyGraph = new HashMap<String, ArrayList<String>>(); + + /** + * Create a DAG from the registrations. + * + * @param dataSetRegistrations + */ + public NewExternalDataDAG(List<? extends NewExternalData> dataSetRegistrations) + { + super(); + this.dataSetRegistrations = dataSetRegistrations; + constructGraph(); + } + + /** + * @return The registrations ordered topologically such that each registrations comes after the + * ones it depends on. + */ + public List<? extends NewExternalData> getOrderedRegistrations() + { + DAG<String, ArrayList<String>> dag = new DAG<String, ArrayList<String>>(dependencyGraph); + List<String> sortedCodes = dag.sortTopologically(); + ArrayList<NewExternalData> sortedData = new ArrayList<NewExternalData>(); + for (String code : sortedCodes) + { + NewExternalData data = codeToDataMap.get(code); + // Some of the dependencies may be to *existing* data -- we don't care about those here. + if (null != data) + { + sortedData.add(data); + } + } + + return sortedData; + } + + /** + * Sort the registrations topologically. + */ + private void constructGraph() + { + for (NewExternalData dataSet : dataSetRegistrations) + { + String dataSetCode = dataSet.getCode(); + codeToDataMap.put(dataSetCode, dataSet); + + // There may already be dependents for this data set -- get them or initialize the + // dependents + ArrayList<String> dependents = getDependentsList(dataSetCode); + + // All the parents are dependents + dependents.addAll(dataSet.getParentDataSetCodes()); + + if (dataSet instanceof NewContainerDataSet) + { + // This data set is a dependent on each of the contained ones + List<String> containedDataSetCodes = + ((NewContainerDataSet) dataSet).getContainedDataSetCodes(); + for (String containedDataSetCode : containedDataSetCodes) + { + ArrayList<String> containedDependents = getDependentsList(containedDataSetCode); + containedDependents.add(dataSetCode); + } + } + + dependencyGraph.put(dataSet.getCode(), dependents); + } + } + + private ArrayList<String> getDependentsList(String dataSetCode) + { + ArrayList<String> dependents = dependencyGraph.get(dataSetCode); + if (null == dependents) + { + dependents = new ArrayList<String>(); + dependencyGraph.put(dataSetCode, dependents); + } + return dependents; + } + +}