blob: 88998d3e6cc6fe562436736acd66f10409e464d1 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
package org.eclipse.mdm.apicopy.control;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.mdm.api.base.Transaction;
import org.eclipse.mdm.api.base.adapter.EntityType;
import org.eclipse.mdm.api.base.adapter.Relation;
import org.eclipse.mdm.api.base.massdata.ReadRequest;
import org.eclipse.mdm.api.base.massdata.ReadRequest.ValuesMode;
import org.eclipse.mdm.api.base.massdata.WriteRequest;
import org.eclipse.mdm.api.base.model.Channel;
import org.eclipse.mdm.api.base.model.ChannelGroup;
import org.eclipse.mdm.api.base.model.ContextComponent;
import org.eclipse.mdm.api.base.model.ContextRoot;
import org.eclipse.mdm.api.base.model.ContextType;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.MeasuredValues;
import org.eclipse.mdm.api.base.model.Measurement;
import org.eclipse.mdm.api.base.model.Quantity;
import org.eclipse.mdm.api.base.model.Test;
import org.eclipse.mdm.api.base.model.TestStep;
import org.eclipse.mdm.api.base.model.Unit;
import org.eclipse.mdm.api.base.model.User;
import org.eclipse.mdm.api.base.model.Value;
import org.eclipse.mdm.api.base.model.VersionState;
import org.eclipse.mdm.api.dflt.ApplicationContext;
import org.eclipse.mdm.api.dflt.EntityManager;
import org.eclipse.mdm.api.dflt.model.Classification;
import org.eclipse.mdm.api.dflt.model.Pool;
import org.eclipse.mdm.api.dflt.model.Project;
import org.eclipse.mdm.api.dflt.model.TemplateComponent;
import org.eclipse.mdm.api.dflt.model.TemplateRoot;
import org.eclipse.mdm.api.dflt.model.TemplateTest;
import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
import org.eclipse.mdm.api.dflt.model.Versionable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
import com.google.common.collect.ListMultimap;
public class ImportTask extends TransferBase implements ApiCopyTask {
/**
* Property to configure to overwrite the existing test step
*
* Default: false
*
* If true and the matching target test step exists, context data will be
* overwritten and the measurements will be imported as children of the existing
* teststep.
*
* Otherwise a new test step will be created
*/
private static final String PROPERTY_OVERWRITE_EXISTING_ELEMENTS = "overwriteExistingElements";
private static final String DEFAULT_OVERWRITE_EXISTING_ELEMENTS = "false";
/**
* Property to configure that existing measured values will be appended
*
* Default: false
*
* If true the measured value of the import data set will be appended to the
* existing. That means, if the target measurement already exists the importer
* will add the measured values of the source column to the target column. If at
* the the target measurement the column not exists, the importer create a new
* one, add first invalid values with the count of the target submatrix size,
* and add there the source values.
*
* If false and the target measurement already exists, the import task will be
* canceled
*/
private static final String PROPERTY_APPEND = "append";
private static final String DEFAULT_APPEND = "false";
/**
* Property to configure that existing file links will be replaced
*
* Default: false
*
* If true, file links of the target entities will be replaced, if in the source
* the file link exists
*
* Otherwise new file links will be added to the existing sequence.
*/
private static final String PROPERTY_REPLACE_FILELINKS = "replaceFileLinks";
private static final String DEFAULT_REPLACE_FILES = "false";
private static final Logger LOG = LoggerFactory.getLogger(ImportTask.class);
private ClassificationUtil classificationUtil;
private TemplateManager templateManager;
private Map<String, String> quantityMapping = new HashMap<>();
private Map<String, String> unitMapping = new HashMap<>();
private Map<String, String> properties = new HashMap<>();
private boolean replaceFileLinks = false;
public ImportTask(ApplicationContext src, ApplicationContext dst, TemplateManager templateManager) {
super(src, dst);
if (templateManager == null) {
this.templateManager = new DefaultTemplateManager();
} else {
this.templateManager = templateManager;
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.mdm.apicopy.control.ApiCopyTask#setUnitMapping(java.util.Map)
*/
@Override
public void setUnitMapping(Map<String, String> unitMapping) {
this.unitMapping = unitMapping;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.mdm.apicopy.control.ApiCopyTask#setQuantityMapping(java.util.Map)
*/
@Override
public void setQuantityMapping(Map<String, String> quantityMapping) {
this.quantityMapping = quantityMapping;
}
@Override
public void copy(List<? extends Entity> entities) {
Transaction transaction = entityManagerDst.startTransaction();
classificationUtil = new ClassificationUtil(transaction, contextDst);
try {
mapSrcDstEntities.clear();
ListMultimap<Class<? extends Entity>, Entity> parents = loadParents(entities);
LOG.trace("Resolved parents: {}", parents);
supportedRootEntities.forEach(ec -> parents.get(ec).forEach(e -> copyEntity(e, false, transaction)));
LOG.trace("Import entities: {}", entities);
entities.forEach(e -> copyEntity(e, true, transaction));
transaction.commit();
deleteFilesOfReplacedFileLinks();
} catch (Exception exc) {
try {
transaction.abort();
} catch (Exception exc2) {
LOG.error("Could not abort transaction!");
}
deleteFilesOfUploadedFileLinks();
throw new ApiCopyException("Could not copy data: " + exc.getMessage(), exc);
} finally {
classificationUtil.clearCache();
clearReplacedFileLinkCache();
clearUploadedFileLinkCache();
deleteLocalTempFiles();
}
}
@Override
public boolean isReplaceFileLinks() {
return replaceFileLinks;
}
private Entity copyEntity(Entity entity, boolean recursive, Transaction transaction) {
if (entity instanceof Project) {
return copyProject((Project) entity, recursive, transaction);
} else if (entity instanceof Pool) {
return copyPool((Pool) entity, recursive, transaction);
} else if (entity instanceof Test) {
return copyTest((Test) entity, recursive, transaction);
} else if (entity instanceof TestStep) {
return copyTestStep((TestStep) entity, recursive, transaction);
} else if (entity instanceof Measurement) {
return copyMeasurement((Measurement) entity, new ArrayList<ContextRoot>(), recursive, transaction);
} else {
throw new ApiCopyException("Unsupported entity: '" + entity.getClass().getName() + "'");
}
}
private Project copyProject(Project projectSrc, boolean recursive, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(projectSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
Optional<Project> projectOpt = fetchOne(entityManagerDst, Project.class, projectSrc.getName());
if (projectOpt.isPresent()) {
LOG.trace("Project '{}' already exists.", projectSrc.getName());
ehDst = new EntityHolder(projectOpt.get(), entityManagerDst);
} else {
LOG.trace("Importing Project '{}'.", projectSrc.getName());
Project projectDst = entityFactoryDst.createProject(projectSrc.getName());
copyValues(projectSrc, projectDst, Arrays.asList("Id", "Name"), false);
persist(transaction, projectDst);
ehDst = new EntityHolder(projectDst, entityManagerDst);
}
mapSrcDstEntities.put(ehSrc, ehDst);
if (recursive) {
entityManagerSrc.loadChildren(projectSrc, Pool.class)
.forEach(pool -> copyPool(pool, recursive, transaction));
}
}
return (Project) ehDst.getEntity();
}
private Pool copyPool(Pool poolSrc, boolean recursive, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(poolSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
LOG.trace("Importing Pool '{}'", poolSrc.getName());
Project projectParentDst = (Project) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(poolSrc, Project.class).get(), entityManagerSrc))
.getEntity();
Optional<Pool> poolOpt = fetchChild(entityManagerDst, projectParentDst, Pool.class, poolSrc.getName());
if (poolOpt.isPresent()) {
LOG.trace("Pool '{}' already exists.", poolSrc.getName());
ehDst = new EntityHolder(poolOpt.get(), entityManagerDst);
} else {
LOG.trace("Importing Pool '{}'.", poolSrc.getName());
Pool poolDst = entityFactoryDst.createPool(poolSrc.getName(), projectParentDst);
copyValues(poolSrc, poolDst, Arrays.asList("Id", "Name"), false);
persist(transaction, poolDst);
ehDst = new EntityHolder(poolDst, entityManagerDst);
}
mapSrcDstEntities.put(ehSrc, ehDst);
if (recursive) {
entityManagerSrc.loadChildren(poolSrc, Test.class)
.forEach(test -> copyTest(test, recursive, transaction));
}
}
return (Pool) ehDst.getEntity();
}
private Test copyTest(Test testSrc, boolean recursive, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(testSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
Pool poolParentDst = (Pool) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(testSrc, Pool.class).get(), entityManagerSrc))
.getEntity();
Optional<TemplateTest> templateTestDst = loadTemplateTest(testSrc);
String rootProjectName = getProjectName(testSrc, entityManagerSrc);
Optional<Test> testOpt = fetchChild(entityManagerDst, poolParentDst, Test.class, testSrc.getName());
if (testOpt.isPresent()) {
LOG.trace("Test '{}' already exists.", testSrc.getName());
ehDst = new EntityHolder(testOpt.get(), entityManagerDst);
} else {
Test testDst;
if (templateTestDst.isPresent()) {
LOG.trace("Importing Test '{}' using TestTemplate '{}'", testSrc.getName(),
templateTestDst.get().getName());
testDst = entityFactoryDst.createTest(testSrc.getName(), poolParentDst, templateTestDst.get(),
classificationUtil.getClassification(rootProjectName), false);
} else {
LOG.trace("Importing Test '{}' using no TestTemplate", testSrc.getName());
testDst = entityFactoryDst.createTest(testSrc.getName(), poolParentDst, null,
classificationUtil.getClassification(rootProjectName), false);
}
copyValues(testSrc, testDst, Arrays.asList("Id", "Name"), true);
// copy responsible person:
Optional<User> userSrc = testSrc.getResponsiblePerson();
if (userSrc.isPresent()) {
User userDst = entityManagerDst.loadAll(User.class, userSrc.get().getName()).stream().findFirst()
.orElseThrow(() -> new ApiCopyException(String.format(
"No User instance with name %s found in destination!", userSrc.get().getName())));
testDst.setResponsiblePerson(userDst);
}
persist(transaction, testDst);
ehDst = new EntityHolder(testDst, entityManagerDst);
}
mapSrcDstEntities.put(ehSrc, ehDst);
if (recursive) {
EntityType etTestStep = modelManagerDst.getEntityType(TestStep.class);
EntityType etTest = modelManagerDst.getEntityType(Test.class);
Relation relTest = etTestStep.getRelation(etTest);
if (null == relTest) {
throw new ApiCopyException("No relation to Test found at TestStep!");
}
copyTestSteps(testSrc, recursive, templateTestDst, (Test) ehDst.getEntity(), transaction);
entityManagerSrc.loadChildren(testSrc, TestStep.class)
.forEach(testStep -> copyTestStep(testStep, recursive, transaction));
}
}
return (Test) ehDst.getEntity();
}
private TestStep copyTestStep(TestStep testStepSrc, boolean recursive, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(testStepSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
LOG.trace("Importing TestStep '{}'", testStepSrc.getName());
Test testDst = (Test) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(testStepSrc, Test.class).get(), entityManagerSrc))
.getEntity();
Optional<TemplateTestStep> templateTestStep = loadTemplateTestStep(testStepSrc);
String rootProjectName = getProjectName(testStepSrc, entityManagerSrc);
TestStep testStepDst = fetchChild(entityManagerDst, testDst, TestStep.class, testStepSrc.getName())
.orElseGet(() -> {
if (templateTestStep.isPresent() && hasContextData(testStepSrc)) {
LOG.trace("Importing TestStep '{}' using TestStepTemplate '{}' and create context roots",
testStepSrc.getName(), templateTestStep.get().getName());
return entityFactoryDst.createTestStep(testDst, templateTestStep.get(),
classificationUtil.getClassification(rootProjectName));
} else if (templateTestStep.isPresent()) {
LOG.trace("Importing TestStep '{}' using TestStepTemplate '{}'", testStepSrc.getName(),
templateTestStep.get().getName());
return entityFactoryDst.createTestStepWithOutContextRoots(testDst, templateTestStep.get(),
classificationUtil.getClassification(rootProjectName));
} else {
LOG.trace("Importing TestStep '{}' using no TestStepTemplate", testStepSrc.getName());
TestStep createdTestStep = entityFactoryDst.createTestStep(testStepSrc.getName(), testDst,
classificationUtil.getClassification(rootProjectName));
return createdTestStep;
}
});
copyValues(testStepSrc, testStepDst, Arrays.asList("Id"), true);
persist(transaction, testStepDst);
ehDst = new EntityHolder(testStepDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
Map<ContextType, ContextRoot> mapContextRootsSrc = testStepSrc.loadContexts(entityManagerSrc,
ContextType.values());
Map<ContextType, ContextRoot> mapContextRootsDst = testStepDst.loadContexts(entityManagerDst,
ContextType.values());
copyContext(mapContextRootsSrc, mapContextRootsDst, templateTestStep, transaction);
if (recursive) {
List<ContextRoot> listContextRoots = new ArrayList<>();
entityManagerSrc.loadChildren(testStepSrc, Measurement.class)
.forEach(measurement -> copyMeasurement(measurement, listContextRoots, recursive, transaction));
}
}
return (TestStep) ehDst.getEntity();
}
private String getProjectName(TestStep testStep, EntityManager entityManager) {
Optional<Test> parentTest = entityManager.loadParent(testStep, Test.class);
if (!parentTest.isPresent()) {
throw new ApiCopyException("Parent of source teststep not found!");
}
return getProjectName(parentTest.get(), entityManager);
}
private String getProjectName(Test test, EntityManager entityManager) {
Optional<Pool> parentPool = entityManager.loadParent(test, Pool.class);
if (!parentPool.isPresent()) {
throw new ApiCopyException("Parent of source test not found!");
}
Optional<Project> parentProject = entityManager.loadParent(parentPool.get(), Project.class);
if (!parentProject.isPresent()) {
throw new ApiCopyException("Parent of source pool not found!");
}
return parentProject.get().getName();
}
/**
* Check if the teststep has context data
*
* @param testStepSrc
* @return true if the teststep has conteyt data
*/
private boolean hasContextData(TestStep testStepSrc) {
boolean hasContextData = false;
Optional<EntityManager> entityManager = contextSrc.getEntityManager();
if (entityManager.isPresent()) {
Map<ContextType, ContextRoot> loadContexts = entityManager.get().loadContexts(testStepSrc,
ContextType.UNITUNDERTEST, ContextType.TESTEQUIPMENT, ContextType.TESTSEQUENCE);
if (!loadContexts.isEmpty()) {
hasContextData = true;
}
}
return hasContextData;
}
private List<TestStep> copyTestSteps(Test testSrc, boolean recursive, Optional<TemplateTest> templateTestDst,
Test testDst, Transaction transaction) {
List<TestStep> listTestStepsSrc = entityManagerSrc.loadChildren(testSrc, TestStep.class);
List<TestStep> listTestStepsDst = new ArrayList<>();
for (int i = 0, len = listTestStepsSrc.size(); i < len; ++i) {
TestStep testStepSrc = listTestStepsSrc.get(i);
Optional<TemplateTestStep> templateTestStep = loadTemplateTestStep(testStepSrc);
String rootProjectName = getProjectName(testStepSrc, entityManagerSrc);
Optional<TestStep> oTestSTepDst = fetchChild(entityManagerDst, testDst, TestStep.class,
testStepSrc.getName());
TestStep testStepDst;
boolean overwriteExistingElements = Boolean.valueOf(
properties.getOrDefault(PROPERTY_OVERWRITE_EXISTING_ELEMENTS, DEFAULT_OVERWRITE_EXISTING_ELEMENTS));
if (!overwriteExistingElements || (overwriteExistingElements && !oTestSTepDst.isPresent())) {
if (templateTestStep.isPresent() && hasContextData(testStepSrc)) {
LOG.trace("Importing TestStep '{}' using TestStepTemplate '{}' and create context roots",
testStepSrc.getName(), templateTestStep.get().getName());
testStepDst = entityFactoryDst.createTestStep(testDst, templateTestStep.get(),
classificationUtil.getClassification(rootProjectName));
testStepDst.setName(testStepSrc.getName());
} else if (templateTestStep.isPresent()) {
LOG.trace("Importing TestStep '{}' using TestStepTemplate '{}' and create context roots",
testStepSrc.getName(), templateTestStep.get().getName());
testStepDst = entityFactoryDst.createTestStepWithOutContextRoots(testDst, templateTestStep.get(),
classificationUtil.getClassification(rootProjectName));
} else {
LOG.trace("Importing TestStep '{}' using no TestStepTemplate", testStepSrc.getName());
testStepDst = entityFactoryDst.createTestStep(testStepSrc.getName(), testDst,
classificationUtil.getClassification(rootProjectName));
}
} else {
testStepDst = oTestSTepDst.get();
}
copyValues(testStepSrc, testStepDst, Arrays.asList("Id"), true);
listTestStepsDst.add(testStepDst);
mapSrcDstEntities.put(new EntityHolder(testStepSrc, entityManagerSrc),
new EntityHolder(testStepDst, entityManagerDst));
}
for (TestStep testStepSrc : listTestStepsSrc) {
Optional<TestStep> testStepDst = listTestStepsDst.stream()
.filter(n -> n.getName().equals(testStepSrc.getName())).findFirst();
if (testStepDst.isPresent()) {
Map<ContextType, ContextRoot> mapContextRootsSrc = testStepSrc.loadContexts(entityManagerSrc,
ContextType.values());
Map<ContextType, ContextRoot> mapContextRootsDst = testStepDst.get().loadContexts(entityManagerDst,
ContextType.values());
copyContext(mapContextRootsSrc, mapContextRootsDst, loadTemplateTestStep(testStepSrc), transaction);
}
}
persist(transaction, listTestStepsDst);
if (recursive) {
for (TestStep testStep : listTestStepsSrc) {
List<ContextRoot> listContextRoots = new ArrayList<>();
entityManagerSrc.loadChildren(testStep, Measurement.class)
.forEach(measurement -> copyMeasurement(measurement, listContextRoots, recursive, transaction));
}
}
return listTestStepsDst;
}
private void copyContext(Map<ContextType, ContextRoot> mapContextRootsSrc,
Map<ContextType, ContextRoot> mapContextRootsDst, Optional<TemplateTestStep> optTemplateTestStep,
Transaction transaction) {
for (Map.Entry<ContextType, ContextRoot> me : mapContextRootsSrc.entrySet()) {
LOG.trace("Importing ContextRoot '{}'", me.getKey());
ContextRoot contextRootDst = mapContextRootsDst.get(me.getKey());
if (null != contextRootDst && contextRootDst.getName().equals(me.getValue().getName())) {
ContextRoot contextRootSrc = me.getValue();
copyValues(contextRootSrc, contextRootDst, Arrays.asList("Id", "Name"), false);
TemplateRoot templateRootDst = null;
if (optTemplateTestStep.isPresent()) {
Optional<TemplateRoot> optTemplateRoot = optTemplateTestStep.get()
.getTemplateRoot(contextRootDst.getContextType());
templateRootDst = optTemplateRoot.orElse(null);
}
for (ContextComponent contextComponentSrc : me.getValue().getContextComponents()) {
LOG.trace("Importing ContextComponent '{}'", contextComponentSrc.getName());
Optional<ContextComponent> o = contextRootDst.getContextComponent(contextComponentSrc.getName());
if (o.isPresent()) {
ContextComponent contextComponentDst = o.get();
copyValues(contextComponentSrc, contextComponentDst, Arrays.asList("Id", "Name"), true);
} else if (null != templateRootDst) {
Optional<TemplateComponent> optTemplateComponent = templateRootDst
.getTemplateComponent(contextComponentSrc.getName());
if (optTemplateComponent.isPresent()) {
TemplateComponent templateComponent = optTemplateComponent.get();
if (templateComponent.isOptional() && !templateComponent.isDefaultActive()) {
ContextComponent contextComponentDst = entityFactoryDst
.createContextComponent(contextComponentSrc.getName(), contextRootDst);
copyValues(contextComponentSrc, contextComponentDst, Arrays.asList("Id", "Name"), true);
persist(transaction, contextComponentDst);
}
}
}
}
}
}
}
private Measurement copyMeasurement(Measurement measurementSrc, List<ContextRoot> listContextRootsDst,
boolean recursive, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(measurementSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
boolean append = Boolean.valueOf(properties.getOrDefault(PROPERTY_APPEND, DEFAULT_APPEND));
if (null == ehDst) {
LOG.trace("Importing Measurement '{}'", measurementSrc.getName());
TestStep testStepSrs = entityManagerSrc.loadParent(measurementSrc, TestStep.class).get();
TestStep testStepParentDst = (TestStep) mapSrcDstEntities
.get(new EntityHolder(testStepSrs, entityManagerSrc)).getEntity();
// EntityType etMeasurement = modelManagerDst.getEntityType(Measurement.class);
// EntityType etTestStep = modelManagerDst.getEntityType(TestStep.class);
//
// Relation relTestStep = etMeasurement.getRelation(etTestStep);
//
// if (null == relTestStep) {
// throw new ApiCopyException("No relation to TestStep found at MeaResult!");
// }
//
// Filter filter = Filter.nameOnly(etMeasurement, measurementSrc.getName()).id(relTestStep,
// testStepParentDst.getID());
//
// Optional<Measurement> optMeasurement = fetchOne(searchServiceDst, Measurement.class, filter);
Optional<Measurement> optMeasurement = fetchChild(entityManagerDst, testStepParentDst, Measurement.class,
measurementSrc.getName());
Measurement measurementDst = null;
if (optMeasurement.isPresent() && !append) {
throw new ApiCopyException(String.format("TestStep '%s' has already a measurement with name '%s'!",
testStepParentDst.getName(), measurementSrc.getName()));
} else if (optMeasurement.isPresent()) {
measurementDst = optMeasurement.get();
} else {
append = false;
}
Optional<TemplateTestStep> optTemplateTestStep = loadTemplateTestStep(testStepSrs);
// If no ContextRoots to use with the newly created Measurement are passed into
// this method, use ContextRoots
// of any already existing Measurement under the parent test step.
// First look in destination...
if (listContextRootsDst.isEmpty()) {
for (Measurement existingMeasurementDst : entityManagerDst.loadChildren(testStepParentDst,
Measurement.class)) {
listContextRootsDst.addAll(
existingMeasurementDst.loadContexts(entityManagerDst, ContextType.values()).values());
if (!listContextRootsDst.isEmpty()) {
break;
}
}
}
// ...then, if nothing has been found, in source and try to find destination
// counterpart in cache map:
if (listContextRootsDst.isEmpty()) {
for (Measurement existingMeasurementSrc : entityManagerSrc.loadChildren(testStepSrs,
Measurement.class)) {
EntityHolder eh = mapSrcDstEntities.get(new EntityHolder(existingMeasurementSrc, entityManagerSrc));
if (null != eh) {
listContextRootsDst.addAll(((Measurement) eh.getEntity())
.loadContexts(entityManagerDst, ContextType.values()).values());
}
if (!listContextRootsDst.isEmpty()) {
break;
}
}
}
// Still no ContextRoots found? Create them from the test step template:
if (listContextRootsDst.isEmpty() && optTemplateTestStep.isPresent()) {
optTemplateTestStep.get().getTemplateRoots()
.forEach(tr -> listContextRootsDst.add(entityFactoryDst.createContextRoot(tr)));
}
if (measurementDst == null) {
measurementDst = entityFactoryDst.createMeasurement(measurementSrc.getName(), testStepParentDst,
listContextRootsDst.toArray(new ContextRoot[listContextRootsDst.size()]));
}
copyValues(measurementSrc, measurementDst, Arrays.asList("Id", "Name"), true);
ehDst = new EntityHolder(measurementDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
Map<ContextType, ContextRoot> mapContextRootsSrc = testStepParentDst.loadContexts(entityManagerDst,
ContextType.values());
Map<ContextType, ContextRoot> mapContextRootsDst = measurementDst.loadContexts(entityManagerDst,
ContextType.values());
copyContext(mapContextRootsSrc, mapContextRootsDst, optTemplateTestStep, transaction);
mapContextRootsSrc = measurementSrc.loadContexts(entityManagerSrc, ContextType.values());
mapContextRootsDst = measurementDst.loadContexts(entityManagerDst, ContextType.values());
copyContext(mapContextRootsSrc, mapContextRootsDst, optTemplateTestStep, transaction);
persist(transaction, measurementDst);
String projectName = getProjectName(entityManagerSrc.loadParent(measurementSrc, TestStep.class).get(),
entityManagerSrc);
Classification classification = classificationUtil.getClassification(projectName);
classification.assign(testStepParentDst);
persist(transaction, testStepParentDst);
Iterator<ContextRoot> contextRootIter = mapContextRootsDst.values().iterator();
while (contextRootIter.hasNext()) {
ContextRoot contextRootForUpdate = contextRootIter.next();
persist(transaction, contextRootForUpdate);
}
if (recursive) {
List<Channel> sourceChannels = entityManagerSrc.loadChildren(measurementSrc, Channel.class);
List<WriteRequest> listWriteRequests = new ArrayList<>();
Map<String, Channel> mapChannelsDst = new HashMap<>();
Map<String, Channel> mapChannelsSrc = new HashMap<>();
List<Channel> existingChannels = entityManagerDst.loadChildren(measurementDst, Channel.class);
if (append && !isSrcChannelsValid(sourceChannels, existingChannels)) {
throw new ApiCopyException(
"Appending not possible. All channels of existing measurement have to be in the source measurement");
}
Map<String, Optional<Quantity>> quantitiesByName = preloadQuantities(sourceChannels);
for (Channel channel : sourceChannels) {
Channel channelDst = copyChannel(channel, measurementDst, existingChannels, quantitiesByName,
transaction);
mapChannelsDst.put(channel.getName(), channelDst);
mapChannelsSrc.put(channel.getName(), channel);
}
for (ChannelGroup channelGroupSrc : entityManagerSrc.loadChildren(measurementSrc, ChannelGroup.class)) {
Map<String, MeasuredValues> existingMeasValuesToAppend = new HashMap<>();
Integer numberOfValues = 0;
if (append) {
Optional<ChannelGroup> optChannelGroup = fetchOneChannelGroup(entityManagerSrc,
channelGroupSrc);
if (optChannelGroup.isPresent()) {
numberOfValues = optChannelGroup.get().getNumberOfValues();
existingMeasValuesToAppend = getMeasurementValuesMap(entityManagerDst,
optChannelGroup.get());
}
}
ChannelGroup channelGroupDst = copyChannelGroup(channelGroupSrc, transaction, append);
for (MeasuredValues measuredValues : entityManagerSrc.readMeasuredValues(ReadRequest
.create(channelGroupSrc).valuesMode(ValuesMode.STORAGE).allChannels().allValues())) {
LOG.trace("Importing MeasuredValues '{}'", measuredValues.getName());
if (!mapChannelsDst.containsKey(measuredValues.getName())) {
throw new ApiCopyException(
String.format("Cannot find Channel %s in destination!", measuredValues.getName()));
}
Channel channelDst = mapChannelsDst.get(measuredValues.getName());
String sourceUnitName = unitMapping.getOrDefault(measuredValues.getUnit(),
measuredValues.getUnit());
List<Unit> sourceUnits = entityManagerDst.loadAll(Unit.class, sourceUnitName);
if (sourceUnits == null || sourceUnits.isEmpty()) {
throw new ApiCopyException(
String.format("Unit with name '%s' not found in target!", sourceUnitName));
}
if (append) {
Channel channelSrc = mapChannelsSrc.get(channelDst.getName());
channelDst = replaceChannelDst(channelSrc, channelDst, measurementDst, ehSrc, transaction);
MeasuredValues measuredValuesOld = existingMeasValuesToAppend.get(channelDst.getName());
if (measuredValuesOld == null) {
measuredValuesOld = MeasuredValuesHelper.createEmptyValues(measuredValues.getName(),
measuredValues.getScalarType(), measuredValues.getUnit(),
measuredValues.getSequenceRepresentation(),
measuredValues.getGenerationParameters(), measuredValues.isIndependent(),
measuredValues.getAxisType(), numberOfValues);
}
measuredValues = MeasuredValuesHelper.appenMeasuredValues(measuredValuesOld,
measuredValues);
}
listWriteRequests.add(
createWriteRequest(channelGroupDst, channelDst, measuredValues, sourceUnits.get(0)));
}
}
transaction.writeMeasuredValues(listWriteRequests);
}
}
return (Measurement) ehDst.getEntity();
}
private boolean isSrcChannelsValid(List<Channel> channelsSrc, List<Channel> channelsDst) {
boolean isSrcChannelsValid = true;
Map<String, Channel> sourceMap = new HashMap<>();
channelsSrc.forEach(srcChannel -> sourceMap.put(srcChannel.getName(), srcChannel));
for (Channel channelDst : channelsDst) {
if (sourceMap.get(channelDst.getName()) == null) {
isSrcChannelsValid = false;
break;
}
}
return isSrcChannelsValid;
}
private Channel replaceChannelDst(Channel channelSrc, Channel channelDst, Measurement measurementDst,
EntityHolder ehSrc, Transaction transaction) {
Channel channelNew = entityFactoryDst.createChannel(channelDst.getName(), measurementDst,
channelDst.getQuantity());
copyValues(channelDst, channelNew, Arrays.asList("Id"), false);
persist(transaction, channelNew);
mapSrcDstEntities.put(new EntityHolder(channelSrc, entityManagerSrc),
new EntityHolder(channelNew, entityManagerDst));
transaction.delete(Collections.singletonList(channelDst));
return channelNew;
}
private Map<String, MeasuredValues> getMeasurementValuesMap(EntityManager entityManager,
ChannelGroup channelGroup) {
Map<String, MeasuredValues> returnVal = new HashMap<>();
for (MeasuredValues measuredValues : entityManager.readMeasuredValues(
ReadRequest.create(channelGroup).valuesMode(ValuesMode.STORAGE).allChannels().allValues())) {
returnVal.put(measuredValues.getName(), measuredValues);
}
return returnVal;
}
/**
* Preloads quantities from dst for the supplied Channels from src.
*
* @param srcChannels
* @return
*/
private Map<String, Optional<Quantity>> preloadQuantities(List<Channel> srcChannels) {
LOG.trace("Preloading Quantities.");
// Load quantity names in dst by name
Set<String> quantityNames = srcChannels.stream().map(c -> c.getQuantity().getName())
.map(n -> quantityMapping.getOrDefault(n, n)).collect(Collectors.toSet());
List<Quantity> results = entityManagerDst.loadAll(Quantity.class, quantityNames);
// Find a valid quantity with the highest version
/*
* TODO Quantity should actually implement Versionable, then we could just use
* org.eclipse.mdm.api.dflt.EntityManager.loadLatestValid(Class<T>, String) Bug:
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=553368
*/
Comparator<Quantity> compareByVersion = Comparator
.comparing(q -> Integer.valueOf(q.getValue(Versionable.ATTR_VERSION).extract()));
return results.stream().filter(q -> q.getValue(Versionable.ATTR_VERSION_STATE).extract() == VersionState.VALID)
.collect(Collectors.groupingBy(Quantity::getName, Collectors.maxBy(compareByVersion)));
}
private Optional<ChannelGroup> fetchOneChannelGroup(EntityManager entityManager, ChannelGroup channelGroupSrc) {
Measurement measurementParentDst = (Measurement) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(channelGroupSrc, Measurement.class).get(),
entityManagerSrc))
.getEntity();
return fetchChild(entityManager, measurementParentDst, ChannelGroup.class, channelGroupSrc.getName());
}
private ChannelGroup copyChannelGroup(ChannelGroup channelGroupSrc, Transaction transaction, boolean append) {
EntityHolder ehSrc = new EntityHolder(channelGroupSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
LOG.trace("Importing ChannelGroup '{}'", channelGroupSrc.getName());
Measurement measurementParentDst = (Measurement) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(channelGroupSrc, Measurement.class).get(),
entityManagerSrc))
.getEntity();
EntityType etChannelGroup = modelManagerDst.getEntityType(ChannelGroup.class);
EntityType etMeasurement = modelManagerDst.getEntityType(Measurement.class);
Relation relMeasurement = etChannelGroup.getRelation(etMeasurement);
if (null == relMeasurement) {
throw new ApiCopyException("No relation to MeaResult found at SubMatrix!");
}
Optional<ChannelGroup> channelGroupOptional = fetchOneChannelGroup(entityManagerDst, channelGroupSrc);
ChannelGroup channelGroupDst = null;
if (append && channelGroupOptional.isPresent()) {
transaction.delete(Collections.singletonList(channelGroupOptional.get()));
channelGroupDst = entityFactoryDst.createChannelGroup(channelGroupSrc.getName(),
channelGroupSrc.getNumberOfValues(), measurementParentDst);
} else {
channelGroupDst = channelGroupOptional
.orElseGet(() -> entityFactoryDst.createChannelGroup(channelGroupSrc.getName(),
channelGroupSrc.getNumberOfValues(), measurementParentDst));
}
copyValues(channelGroupSrc, channelGroupDst, Arrays.asList("Id"), false);
persist(transaction, channelGroupDst);
ehDst = new EntityHolder(channelGroupDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
}
return (ChannelGroup) ehDst.getEntity();
}
private Optional<TemplateTest> loadTemplateTest(Test testSrc) {
Optional<TemplateTest> returnVal = Optional.empty();
String templateTestName = templateManager.getTemplateTestName(testSrc);
if (!Strings.isNullOrEmpty(templateTestName)) {
returnVal = getCurrentValidTestTemplate(entityManagerDst.loadAll(TemplateTest.class, templateTestName));
}
return returnVal;
}
private Optional<TemplateTest> getCurrentValidTestTemplate(List<TemplateTest> listTemplateTests) {
Optional<TemplateTest> returnVal = Optional.empty();
if (listTemplateTests != null && !listTemplateTests.isEmpty()) {
int highestVersion = -1;
TemplateTest highestValidTemplate = null;
for (TemplateTest templateTest : listTemplateTests) {
Value value = templateTest.getValue(TemplateTest.ATTR_VERSION_STATE);
if (VersionState.VALID.equals(value.extract())) {
int version = Integer.parseInt(templateTest.getValue(TemplateTest.ATTR_VERSION).extract());
if (version > highestVersion) {
highestValidTemplate = templateTest;
highestVersion = version;
}
}
}
if (highestValidTemplate != null) {
returnVal = Optional.of(highestValidTemplate);
}
}
return returnVal;
}
private Optional<TemplateTestStep> loadTemplateTestStep(TestStep testStepSrc) {
Optional<TemplateTestStep> returnVal = Optional.empty();
String templateTestStepName = templateManager.getTemplateTestStepName(testStepSrc);
if (!Strings.isNullOrEmpty(templateTestStepName)) {
returnVal = getCurrentValidTestStepTemplate(
entityManagerDst.loadAll(TemplateTestStep.class, templateTestStepName));
}
return returnVal;
}
private Optional<TemplateTestStep> getCurrentValidTestStepTemplate(List<TemplateTestStep> listTemplateTestSteps) {
Optional<TemplateTestStep> returnVal = Optional.empty();
if (listTemplateTestSteps != null && !listTemplateTestSteps.isEmpty()) {
int highestVersion = -1;
TemplateTestStep highestValidTemplate = null;
for (TemplateTestStep templateTestStep : listTemplateTestSteps) {
Value value = templateTestStep.getValue(TemplateTestStep.ATTR_VERSION_STATE);
if (VersionState.VALID.equals(value.extract())) {
int version = Integer.parseInt(templateTestStep.getValue(TemplateTestStep.ATTR_VERSION).extract());
if (version > highestVersion) {
highestValidTemplate = templateTestStep;
highestVersion = version;
}
}
}
if (highestValidTemplate != null) {
returnVal = Optional.of(highestValidTemplate);
}
}
return returnVal;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.mdm.apicopy.control.ApiCopyTask#setProperties(java.util.Map)
*/
@Override
public void setProperties(Map<String, String> properties) {
this.properties = properties;
this.replaceFileLinks = Boolean
.valueOf(this.properties.getOrDefault(PROPERTY_REPLACE_FILELINKS, DEFAULT_REPLACE_FILES));
}
}