blob: 2e810248ba1298da4493166d1c22382974c8f226 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2020 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 org.eclipse.mdm.api.base.ServiceNotProvidedException;
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.User;
import org.eclipse.mdm.api.base.model.Value;
import org.eclipse.mdm.api.base.model.VersionState;
import org.eclipse.mdm.api.base.query.Filter;
import org.eclipse.mdm.api.base.search.SearchService;
import org.eclipse.mdm.api.dflt.ApplicationContext;
import org.eclipse.mdm.api.dflt.EntityManager;
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
* overwriten and the measurements will be imported as childs 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 SearchService searchServiceDst;
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);
searchServiceDst = contextDst.getSearchService()
.orElseThrow(() -> new ServiceNotProvidedException(SearchService.class));
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("Export 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);
} finally {
classificationUtil.clearCache();
clearReplacedFileLinkCache();
clearUploadedFileLinkCache();
}
}
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) {
LOG.trace("Importing Project '{}'", projectSrc.getName());
EntityType etProject = modelManagerDst.getEntityType(Project.class);
Filter filter = Filter.nameOnly(etProject, projectSrc.getName());
Project projectDst = fetchOne(searchServiceDst, Project.class, filter)
.orElseGet(() -> entityFactoryDst.createProject(projectSrc.getName()));
copyValues(projectSrc, projectDst, Arrays.asList("Id", "Name"), false, replaceFileLinks);
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();
EntityType etPool = modelManagerDst.getEntityType(Pool.class);
EntityType etProject = modelManagerDst.getEntityType(Project.class);
Relation relProject = etPool.getRelation(etProject);
if (null == relProject) {
throw new ApiCopyException("No relation to Project found at Pool!");
}
Filter filter = Filter.nameOnly(etPool, poolSrc.getName()).id(relProject, projectParentDst.getID());
Pool poolDst = fetchOne(searchServiceDst, Pool.class, filter)
.orElseGet(() -> entityFactoryDst.createPool(poolSrc.getName(), projectParentDst));
copyValues(poolSrc, poolDst, Arrays.asList("Id", "Name"), false, replaceFileLinks);
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();
EntityType etTest = modelManagerDst.getEntityType(Test.class);
EntityType etPool = modelManagerDst.getEntityType(Pool.class);
Relation relPool = etTest.getRelation(etPool);
if (null == relPool) {
throw new ApiCopyException("No relation to StructureLevel found at Test!");
}
Optional<TemplateTest> templateTestDst = loadTemplateTest(testSrc);
Filter filter = Filter.nameOnly(etTest, testSrc.getName()).id(relPool, poolParentDst.getID());
String rootProjectName = getProjectName(testSrc);
Test testDst;
if (templateTestDst.isPresent()) {
LOG.trace("Importing Test '{}' using TestTemplate '{}'", testSrc.getName(),
templateTestDst.get().getName());
testDst = fetchOne(searchServiceDst, Test.class, filter)
.orElseGet(() -> entityFactoryDst.createTest(testSrc.getName(), poolParentDst,
templateTestDst.get(), classificationUtil.getClassification(rootProjectName), false));
} else {
LOG.trace("Importing Test '{}' using no TestTemplate", testSrc.getName());
testDst = fetchOne(searchServiceDst, Test.class, filter)
.orElseGet(() -> entityFactoryDst.createTest(testSrc.getName(), poolParentDst, null,
classificationUtil.getClassification(rootProjectName), false));
}
copyValues(testSrc, testDst, Arrays.asList("Id", "Name"), true, replaceFileLinks);
// 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);
Relation relTest = etTestStep.getRelation(etTest);
if (null == relTest) {
throw new ApiCopyException("No relation to Test found at TestStep!");
}
copyTestSteps(testSrc, recursive, templateTestDst, testDst, 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());
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!");
}
Test testDst = (Test) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(testStepSrc, Test.class).get(), entityManagerSrc))
.getEntity();
Optional<TemplateTestStep> templateTestStep = loadTemplateTestStep(testStepSrc);
Filter filter = Filter.nameOnly(etTestStep, testStepSrc.getName()).id(relTest, testDst.getID());
String rootProjectName = getProjectName(testStepSrc);
TestStep testStepDst = fetchOne(searchServiceDst, TestStep.class, filter).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));
Value value = createdTestStep.getValue("TplTestStep");
return createdTestStep;
}
});
copyValues(testStepSrc, testStepDst, Arrays.asList("Id"), true, replaceFileLinks);
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 testStepSrc) {
Optional<Test> parentTest = entityManagerSrc.loadParent(testStepSrc, Test.class);
if (!parentTest.isPresent()) {
throw new ApiCopyException("Parent of source teststep not found!");
}
return getProjectName(parentTest.get());
}
private String getProjectName(Test testSrc) {
Optional<Pool> parentPool = entityManagerSrc.loadParent(testSrc, Pool.class);
if (!parentPool.isPresent()) {
throw new ApiCopyException("Parent of source test not found!");
}
Optional<Project> parentProject = entityManagerSrc.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) {
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!");
}
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);
Filter filter = Filter.nameOnly(etTestStep, testStepSrc.getName()).id(relTest, testDst.getID());
Optional<TestStep> oTestSTepDst = fetchOne(searchServiceDst, TestStep.class, filter);
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, replaceFileLinks);
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, replaceFileLinks);
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,
replaceFileLinks);
} 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,
replaceFileLinks);
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);
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, replaceFileLinks);
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);
Iterator<ContextRoot> contextRootIter = mapContextRootsDst.values().iterator();
while (contextRootIter.hasNext()) {
ContextRoot contextRootForUpdate = contextRootIter.next();
persist(transaction, contextRootForUpdate);
}
if (recursive) {
List<WriteRequest> listWriteRequests = new ArrayList<>();
Map<String, Channel> mapChannels = new HashMap<>();
if (append && !isSrcChannelsValid(entityManagerSrc.loadChildren(measurementSrc, Channel.class),
entityManagerDst.loadChildren(measurementDst, Channel.class))) {
throw new ApiCopyException(
"Appending not possible. All channels of existing measurement have to be in the source measurement");
}
for (Channel channel : entityManagerSrc.loadChildren(measurementSrc, Channel.class)) {
Channel channelDst = copyChannel(channel, transaction);
mapChannels.put(channel.getName(), channelDst);
}
for (ChannelGroup channelGroup : entityManagerSrc.loadChildren(measurementSrc, ChannelGroup.class)) {
Map<String, MeasuredValues> existingMeasValuesToAppend = new HashMap<>();
Integer numberOfValues = 0;
if (append) {
Optional<ChannelGroup> optChannelGroup = fetchOneChannelGroup(channelGroup);
if (optChannelGroup.isPresent()) {
numberOfValues = optChannelGroup.get().getNumberOfValues();
existingMeasValuesToAppend = getMeasurementValuesMap(entityManagerDst,
optChannelGroup.get());
}
}
ChannelGroup channelGroupDst = copyChannelGroup(channelGroup, transaction, append);
for (MeasuredValues measuredValues : entityManagerSrc.readMeasuredValues(ReadRequest
.create(channelGroup).valuesMode(ValuesMode.STORAGE).allChannels().allValues())) {
LOG.trace("Importing MeasuredValues '{}'", measuredValues.getName());
if (!mapChannels.containsKey(measuredValues.getName())) {
throw new ApiCopyException(
String.format("Cannot find Channel %s in destination!", measuredValues.getName()));
}
Channel channelDst = mapChannels.get(measuredValues.getName());
String mappedUnit = unitMapping.get(measuredValues.getUnit());
if (!Strings.isNullOrEmpty(mappedUnit)) {
measuredValues = MeasuredValuesHelper.mapUnitOfMeasuredValues(measuredValues, mappedUnit);
}
if (append) {
channelDst = replaceChannelDst(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));
}
}
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 channelDst, Measurement measurementDst, EntityHolder ehSrc,
Transaction transaction) {
Channel channelNew = entityFactoryDst.createChannel(channelDst.getName(), measurementDst,
channelDst.getQuantity());
copyValues(channelDst, channelNew, Arrays.asList("Id"), false, replaceFileLinks);
persist(transaction, channelNew);
mapSrcDstEntities.put(ehSrc, 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;
}
private Channel copyChannel(Channel channelSrc, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(channelSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
LOG.trace("Importing Channel '{}'", channelSrc.getName());
Measurement measurementParentDst = (Measurement) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(channelSrc, Measurement.class).get(),
entityManagerSrc))
.getEntity();
EntityType etChannel = modelManagerDst.getEntityType(Channel.class);
EntityType etMeasurement = modelManagerDst.getEntityType(Measurement.class);
Relation relMeasurement = etChannel.getRelation(etMeasurement);
if (null == relMeasurement) {
throw new ApiCopyException("No relation to MeaResult found at MeaQuantity!");
}
// 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
*/
Quantity quantity = entityManagerDst
.loadAll(Quantity.class,
quantityMapping.getOrDefault(channelSrc.getQuantity().getName(),
channelSrc.getQuantity().getName()))
.stream().filter(q -> q.getValue(Versionable.ATTR_VERSION_STATE).extract() == VersionState.VALID)
.sorted(Comparator.comparing(q -> Integer.valueOf(q.getValue(Versionable.ATTR_VERSION).extract())))
.findFirst().orElseThrow(() -> new ApiCopyException(String
.format("Cannot find Quantity %s in destination!", channelSrc.getQuantity().getName())));
Filter filter = Filter.nameOnly(etChannel, channelSrc.getName()).id(relMeasurement,
measurementParentDst.getID());
Channel channelDst = fetchOne(searchServiceDst, Channel.class, filter).orElseGet(
() -> entityFactoryDst.createChannel(channelSrc.getName(), measurementParentDst, quantity));
copyValues(channelSrc, channelDst, Arrays.asList("Id"), false, replaceFileLinks);
persist(transaction, channelDst);
ehDst = new EntityHolder(channelDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
}
return (Channel) ehDst.getEntity();
}
private Optional<ChannelGroup> fetchOneChannelGroup(ChannelGroup channelGroupSrc) {
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!");
}
Filter filter = Filter.nameOnly(etChannelGroup, channelGroupSrc.getName()).id(relMeasurement,
measurementParentDst.getID());
return fetchOne(searchServiceDst, ChannelGroup.class, filter);
}
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(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, replaceFileLinks);
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));
}
}