blob: bcc916c3d9a3b9d26f97c8049b218e40f3c9f1d1 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2018 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
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.ContextDescribable;
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.query.Filter;
import org.eclipse.mdm.api.base.search.SearchService;
import org.eclipse.mdm.api.dflt.ApplicationContext;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ListMultimap;
public class AtfxImportTask extends AtfxTransferBase implements ApiCopyTask {
private static final Logger LOG = LoggerFactory.getLogger(AtfxImportTask.class);
private SearchService searchServiceDst;
private TemplateResolver templateResolver;
public AtfxImportTask(ApplicationContext src, ApplicationContext dst) {
super(src, dst);
searchServiceDst = contextDst.getSearchService()
.orElseThrow(() -> new ServiceNotProvidedException(SearchService.class));
templateResolver = new TemplateResolver(entityManagerDst);
}
@Override
public void copy(List<? extends Entity> entities) {
Transaction transaction = entityManagerDst.startTransaction();
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();
} catch (Exception exc) {
try {
transaction.abort();
} catch (Exception exc2) {
LOG.error("Could not abort transaction!");
}
throw new ApiCopyException("Could not copy data.", exc);
}
// QnD, can't be done above due to lack of security support in MDM5,
// has to use ODS interface and transaction of its own:
new ClassificationUtil(contextDst).attachClassification(
mapSrcDstEntities.values().stream().map(eh -> eh.getEntity()).collect(Collectors.toList()));
}
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) {
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"));
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) {
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"));
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 = templateResolver.resolveTemplateTest();
Filter filter = Filter.nameOnly(etTest, testSrc.getName()).id(relPool, poolParentDst.getID());
Test testDst;
if (templateTestDst.isPresent()) {
testDst = fetchOne(searchServiceDst, Test.class, filter).orElseGet(
() -> entityFactoryDst.createTest(testSrc.getName(), poolParentDst, templateTestDst.get()));
} else {
testDst = fetchOne(searchServiceDst, Test.class, filter)
.orElseGet(() -> entityFactoryDst.createTest(testSrc.getName(), poolParentDst));
}
copyValues(testSrc, testDst, Arrays.asList("Id", "Name"));
// 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) {
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 = templateResolver
.resolveTemplateTestStep(templateResolver.resolveTemplateTest());
Filter filter = Filter.nameOnly(etTestStep, testStepSrc.getName()).id(relTest, testDst.getID());
TestStep testStepDst = fetchOne(searchServiceDst, TestStep.class, filter).orElseGet(() -> {
if (templateTestStep.isPresent()) {
return entityFactoryDst.createTestStep(testDst, templateTestStep.get());
} else {
return entityFactoryDst.createTestStep(testStepSrc.getName(), testDst);
}
});
copyValues(testStepSrc, testStepDst, Arrays.asList("Id"));
persist(transaction, testStepDst);
ehDst = new EntityHolder(testStepDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
copyContext(testStepSrc, testStepDst, 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 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 = templateResolver
.resolveTemplateTestStep(templateTestDst.get());
TestStep testStepDst;
if (templateTestStep.isPresent()) {
testStepDst = entityFactoryDst.createTestStep(testDst, templateTestStep.get());
} else {
testStepDst = entityFactoryDst.createTestStep(testSrc.getName(), testDst);
}
copyValues(testStepSrc, testStepDst, Arrays.asList("Id"));
listTestStepsDst.add(testStepDst);
mapSrcDstEntities.put(new EntityHolder(testStepSrc, entityManagerSrc),
new EntityHolder(testStepDst, entityManagerDst));
}
transaction.create(listTestStepsDst);
for (TestStep testStepSrc : listTestStepsSrc) {
Optional<TestStep> testStepDst = listTestStepsDst.stream()
.filter(n -> n.getName().equals(testStepSrc.getName())).findFirst();
if (testStepDst.isPresent()) {
copyContext(testStepSrc, testStepDst.get(), templateResolver.resolveTemplateTestStep(templateTestDst),
transaction);
}
}
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(ContextDescribable contextDescribableSrc, ContextDescribable contextDescribableDst,
Optional<TemplateTestStep> optTemplateTestStep, Transaction transaction) {
List<Entity> listUpdatedEntities = new ArrayList<>();
List<Entity> listCreatedEntities = new ArrayList<>();
Map<ContextType, ContextRoot> mapContextRootsDst = contextDescribableDst.loadContexts(entityManagerDst,
ContextType.values());
for (Map.Entry<ContextType, ContextRoot> me : contextDescribableSrc
.loadContexts(entityManagerSrc, ContextType.values()).entrySet()) {
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"));
TemplateRoot templateRootDst = null;
if (optTemplateTestStep.isPresent()) {
Optional<TemplateRoot> optTemplateRoot = optTemplateTestStep.get()
.getTemplateRoot(contextRootDst.getContextType());
templateRootDst = optTemplateRoot.orElse(null);
}
for (ContextComponent contextComponentSrc : me.getValue().getContextComponents()) {
Optional<ContextComponent> o = contextRootDst.getContextComponent(contextComponentSrc.getName());
if (o.isPresent()) {
ContextComponent contextComponentDst = o.get();
copyValues(contextComponentSrc, contextComponentDst, Arrays.asList("Id", "Name"));
listUpdatedEntities.add(contextComponentDst);
} 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"));
listCreatedEntities.add(contextComponentDst);
}
}
}
}
}
if (null != contextRootDst) {
listUpdatedEntities.add(contextRootDst);
}
}
transaction.create(listCreatedEntities);
transaction.update(listUpdatedEntities);
}
private Measurement copyMeasurement(Measurement measurementSrc, List<ContextRoot> listContextRootsDst,
boolean recursive, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(measurementSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
TestStep testStepParentDst = (TestStep) mapSrcDstEntities
.get(new EntityHolder(entityManagerSrc.loadParent(measurementSrc, TestStep.class).get(),
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<TemplateTestStep> optTemplateTestStep = templateResolver
.resolveTemplateTestStep(templateResolver.resolveTemplateTest());
// 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.size() == 0) {
for (Measurement existingMeasurementDst : entityManagerDst.loadChildren(testStepParentDst,
Measurement.class)) {
listContextRootsDst.addAll(
existingMeasurementDst.loadContexts(entityManagerDst, ContextType.values()).values());
if (listContextRootsDst.size() > 0) {
break;
}
}
}
// ...then, if nothing has been found, in source and try to find destination
// counterpart in cache map:
if (listContextRootsDst.size() == 0) {
for (Measurement existingMeasurementSrc : entityManagerSrc.loadChildren(
entityManagerSrc.loadParent(measurementSrc, TestStep.class).get(), 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.size() > 0) {
break;
}
}
}
// Still no ContextRoots found? Create them from the test step template:
if (listContextRootsDst.size() == 0 && optTemplateTestStep.isPresent()) {
optTemplateTestStep.get().getTemplateRoots()
.forEach(tr -> listContextRootsDst.add(entityFactoryDst.createContextRoot(tr)));
}
Measurement measurementDst = fetchOne(searchServiceDst, Measurement.class, filter)
.orElseGet(() -> entityFactoryDst.createMeasurement(measurementSrc.getName(), testStepParentDst,
listContextRootsDst.toArray(new ContextRoot[listContextRootsDst.size()])));
copyValues(measurementSrc, measurementDst, Arrays.asList("Id", "Name"));
persist(transaction, measurementDst);
ehDst = new EntityHolder(measurementDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
copyContext(measurementSrc, measurementDst, optTemplateTestStep, transaction);
if (recursive) {
List<WriteRequest> listWriteRequests = new ArrayList<>();
Map<String, Channel> mapChannels = new HashMap<>();
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)) {
ChannelGroup channelGroupDst = copyChannelGroup(channelGroup, transaction);
for (MeasuredValues measuredValues : entityManagerSrc.readMeasuredValues(ReadRequest
.create(channelGroup).valuesMode(ValuesMode.STORAGE).allChannels().allValues())) {
if (!mapChannels.containsKey(measuredValues.getName())) {
throw new ApiCopyException(
String.format("Cannot find Channel %s in destination!", measuredValues.getName()));
}
Channel channelDst = mapChannels.get(measuredValues.getName());
listWriteRequests.add(createWriteRequest(channelGroupDst, channelDst, measuredValues));
}
}
transaction.writeMeasuredValues(listWriteRequests);
}
}
return (Measurement) ehDst.getEntity();
}
private Channel copyChannel(Channel channelSrc, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(channelSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
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!");
}
List<Quantity> listQuantities = entityManagerDst.loadAll(Quantity.class,
channelSrc.getQuantity().getName());
if (listQuantities.size() != 1) {
throw 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(measurementParentDst, listQuantities.get(0)));
copyValues(channelSrc, channelDst, Arrays.asList("Id"));
persist(transaction, channelDst);
ehDst = new EntityHolder(channelDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
}
return (Channel) ehDst.getEntity();
}
private ChannelGroup copyChannelGroup(ChannelGroup channelGroupSrc, Transaction transaction) {
EntityHolder ehSrc = new EntityHolder(channelGroupSrc, entityManagerSrc);
EntityHolder ehDst = mapSrcDstEntities.get(ehSrc);
if (null == ehDst) {
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());
ChannelGroup channelGroupDst = fetchOne(searchServiceDst, ChannelGroup.class, filter)
.orElseGet(() -> entityFactoryDst.createChannelGroup(channelGroupSrc.getName(),
channelGroupSrc.getNumberOfValues(), measurementParentDst));
copyValues(channelGroupSrc, channelGroupDst, Arrays.asList("Id"));
persist(transaction, channelGroupDst);
ehDst = new EntityHolder(channelGroupDst, entityManagerDst);
mapSrcDstEntities.put(ehSrc, ehDst);
}
return (ChannelGroup) ehDst.getEntity();
}
}