| /******************************************************************************** |
| * Copyright (c) 2015-2019 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.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.mdm.api.base.Transaction; |
| 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.ContextSensor; |
| 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.PhysicalDimension; |
| 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.dflt.ApplicationContext; |
| import org.eclipse.mdm.api.dflt.model.CatalogAttribute; |
| import org.eclipse.mdm.api.dflt.model.CatalogComponent; |
| import org.eclipse.mdm.api.dflt.model.CatalogSensor; |
| import org.eclipse.mdm.api.dflt.model.Pool; |
| import org.eclipse.mdm.api.dflt.model.Project; |
| import org.eclipse.mdm.api.dflt.model.TemplateRoot; |
| import org.eclipse.mdm.api.dflt.model.TemplateTestStep; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.collect.ListMultimap; |
| |
| public class ExportTask extends TransferBase implements ApiCopyTask { |
| private static final Logger LOG = LoggerFactory.getLogger(ExportTask.class); |
| |
| public ExportTask(ApplicationContext src, ApplicationContext dst) { |
| super(src, dst); |
| } |
| |
| @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("Importing 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); |
| } |
| } |
| |
| 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, 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("Exporting Project '{}'", projectSrc.getName()); |
| Project projectDst = 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) { |
| LOG.trace("Exporting Pool '{}'", poolSrc.getName()); |
| Project projectParentDst = (Project) mapSrcDstEntities |
| .get(new EntityHolder(entityManagerSrc.loadParent(poolSrc, Project.class).get(), entityManagerSrc)) |
| .getEntity(); |
| |
| Pool poolDst = 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) { |
| LOG.trace("Exporting Test '{}'", testSrc.getName()); |
| Pool poolParentDst = (Pool) mapSrcDstEntities |
| .get(new EntityHolder(entityManagerSrc.loadParent(testSrc, Pool.class).get(), entityManagerSrc)) |
| .getEntity(); |
| |
| Test testDst = entityFactoryDst.createTest(testSrc.getName(), poolParentDst); |
| |
| copyValues(testSrc, testDst, Arrays.asList("Id", "Name")); |
| |
| persist(transaction, testDst); |
| |
| ehDst = new EntityHolder(testDst, entityManagerDst); |
| mapSrcDstEntities.put(ehSrc, ehDst); |
| |
| if (recursive) { |
| 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("Exporting TestStep '{}'", testStepSrc.getName()); |
| Test testParentDst = (Test) mapSrcDstEntities |
| .get(new EntityHolder(entityManagerSrc.loadParent(testStepSrc, Test.class).get(), entityManagerSrc)) |
| .getEntity(); |
| |
| TestStep testStepDst = entityFactoryDst.createTestStep(testStepSrc.getName(), testParentDst); |
| |
| copyValues(testStepSrc, testStepDst, Arrays.asList("Id", "Name")); |
| |
| persist(transaction, testStepDst); |
| |
| TemplateTestStep tpl = entityManagerSrc.loadTemplate(testStepSrc).orElseThrow(() -> new ApiCopyException( |
| "Could not retrieve TemplateTestStep for TestStep " + testStepSrc.getID())); |
| |
| copyContext(testStepSrc, testStepDst, tpl, transaction); |
| |
| ehDst = new EntityHolder(testStepDst, entityManagerDst); |
| mapSrcDstEntities.put(ehSrc, ehDst); |
| |
| if (recursive) { |
| entityManagerSrc.loadChildren(testStepSrc, Measurement.class) |
| .forEach(measurement -> copyMeasurement(measurement, recursive, transaction)); |
| } |
| } |
| |
| return (TestStep) ehDst.getEntity(); |
| } |
| |
| private Measurement copyMeasurement(Measurement measurementSrc, boolean recursive, Transaction transaction) { |
| EntityHolder ehSrc = new EntityHolder(measurementSrc, entityManagerSrc); |
| |
| EntityHolder ehDst = mapSrcDstEntities.get(ehSrc); |
| |
| if (null == ehDst) { |
| LOG.trace("Exporting Measurement '{}'", measurementSrc.getName()); |
| TestStep testStepParentSrc = entityManagerSrc.loadParent(measurementSrc, TestStep.class).get(); |
| |
| TestStep testStepParentDst = (TestStep) mapSrcDstEntities |
| .get(new EntityHolder(testStepParentSrc, entityManagerSrc)).getEntity(); |
| |
| Measurement measurementDst = entityFactoryDst.createMeasurement(measurementSrc.getName(), |
| testStepParentDst); |
| |
| copyValues(measurementSrc, measurementDst, Arrays.asList("Id", "Name")); |
| |
| persist(transaction, measurementDst); |
| |
| TemplateTestStep tpl = entityManagerSrc.loadTemplate(testStepParentSrc) |
| .orElseThrow(() -> new ApiCopyException( |
| "Could not retrieve TemplateTestStep for Measurement + " + measurementSrc.getID())); |
| |
| copyContext(measurementSrc, measurementDst, tpl, transaction); |
| |
| ehDst = new EntityHolder(measurementDst, entityManagerDst); |
| mapSrcDstEntities.put(ehSrc, ehDst); |
| |
| 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())) { |
| LOG.trace("Exporting 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()); |
| |
| listWriteRequests.add(createWriteRequest(channelGroupDst, channelDst, measuredValues)); |
| } |
| } |
| |
| transaction.writeMeasuredValues(listWriteRequests); |
| } |
| } |
| |
| return (Measurement) ehDst.getEntity(); |
| } |
| |
| private void copyContext(ContextDescribable entitySrc, ContextDescribable entityDst, TemplateTestStep tpl, |
| Transaction transaction) { |
| |
| for (ContextRoot root : entitySrc.loadContexts(entityManagerSrc).values()) { |
| LOG.trace("Exporting ContextRoot '{}'", root.getName()); |
| TemplateRoot tplRoot = tpl.getTemplateRoot(root.getContextType()) |
| .orElseThrow(() -> new ApiCopyException("Could not retrieve TemplateRoot " + root.getContextType() |
| + " for TestStep + " + entitySrc.getID())); |
| |
| ContextRoot rootDst; |
| if (entityDst instanceof TestStep) { |
| rootDst = entityFactoryDst.createContextRoot((TestStep) entityDst, tplRoot); |
| } else if (entityDst instanceof Measurement) { |
| rootDst = entityFactoryDst.createContextRoot((Measurement) entityDst, tplRoot); |
| } else { |
| throw new ApiCopyException("ContextDescribable must be of instance TestStep or Measurement!"); |
| } |
| |
| copyValues(root, rootDst, Arrays.asList("Id", "Name")); |
| persist(transaction, rootDst); |
| |
| for (ContextComponent comp : root.getContextComponents()) { |
| LOG.trace("Exporting ContextComponent '{}'", comp.getName()); |
| rootDst.getContextComponent(comp.getName()).ifPresent(c -> { |
| copyValues(comp, c, Arrays.asList("Id", "Name")); |
| persist(transaction, c); |
| }); |
| } |
| for (ContextSensor sensor : root.getContextSensors()) { |
| LOG.trace("Exporting ContextSensor '{}'", sensor.getName()); |
| // Parent should be already created above |
| ContextComponent parentDst = rootDst.getContextComponent(sensor.getContextComponent().getName()) |
| .orElseThrow(() -> new ApiCopyException( |
| "Parent ContextComponent of sensor " + sensor.getName() + " not found!")); |
| |
| ContextSensor sensorDst = parentDst.getContextSensor(sensor.getName()).orElseThrow( |
| () -> new ApiCopyException("ContextSensor '" + sensor.getName() + "' not found in target!")); |
| copyValues(sensor, sensorDst, Arrays.asList("Id", "Name")); |
| persist(transaction, sensorDst); |
| } |
| } |
| |
| persist(transaction, entityDst); |
| } |
| |
| private Channel copyChannel(Channel channelSrc, Transaction transaction) { |
| EntityHolder ehSrc = new EntityHolder(channelSrc, entityManagerSrc); |
| |
| EntityHolder ehDst = mapSrcDstEntities.get(ehSrc); |
| |
| if (null == ehDst) { |
| LOG.trace("Exporting Channel '{}'", channelSrc.getName()); |
| Measurement measurementParentDst = (Measurement) mapSrcDstEntities |
| .get(new EntityHolder(entityManagerSrc.loadParent(channelSrc, Measurement.class).get(), |
| entityManagerSrc)) |
| .getEntity(); |
| |
| Quantity quantitySrc = channelSrc.getQuantity(); |
| Unit unitSrc = quantitySrc.getDefaultUnit(); |
| PhysicalDimension physicalDimensionSrc = unitSrc.getPhysicalDimension(); |
| |
| PhysicalDimension physicalDimensionDst = fetchOne(entityManagerDst, PhysicalDimension.class, |
| physicalDimensionSrc.getName()) |
| .orElseGet(() -> entityFactoryDst.createPhysicalDimension(physicalDimensionSrc.getName())); |
| |
| if (isNewEntity(physicalDimensionDst)) { |
| copyValues(physicalDimensionSrc, physicalDimensionDst, Arrays.asList("Id", "Name")); |
| persist(transaction, physicalDimensionDst); |
| } |
| |
| Unit unitDst = fetchOne(entityManagerDst, Unit.class, unitSrc.getName()) |
| .orElseGet(() -> entityFactoryDst.createUnit(unitSrc.getName(), physicalDimensionDst)); |
| |
| if (isNewEntity(unitDst)) { |
| copyValues(unitSrc, unitDst, Arrays.asList("Id", "Name")); |
| persist(transaction, unitDst); |
| } |
| |
| Quantity quantityDst = fetchOne(entityManagerDst, Quantity.class, quantitySrc.getName()) |
| .orElseGet(() -> entityFactoryDst.createQuantity(quantitySrc.getName(), unitDst)); |
| |
| if (isNewEntity(quantityDst)) { |
| copyValues(quantitySrc, quantityDst, Arrays.asList("Id", "Name")); |
| persist(transaction, quantityDst); |
| } |
| |
| Channel channelDst = entityFactoryDst.createChannel(channelSrc.getName(), measurementParentDst, |
| quantityDst); |
| |
| copyValues(channelSrc, channelDst, Arrays.asList("Id", "Name")); |
| |
| 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) { |
| LOG.trace("Exporting ChannelGroup '{}'", channelGroupSrc.getName()); |
| Measurement measurementParentDst = (Measurement) mapSrcDstEntities |
| .get(new EntityHolder(entityManagerSrc.loadParent(channelGroupSrc, Measurement.class).get(), |
| entityManagerSrc)) |
| .getEntity(); |
| |
| ChannelGroup channelGroupDst = entityFactoryDst.createChannelGroup(channelGroupSrc.getName(), |
| channelGroupSrc.getNumberOfValues(), measurementParentDst); |
| |
| copyValues(channelGroupSrc, channelGroupDst, Arrays.asList("Id", "Name")); |
| |
| persist(transaction, channelGroupDst); |
| |
| ehDst = new EntityHolder(channelGroupDst, entityManagerDst); |
| mapSrcDstEntities.put(ehSrc, ehDst); |
| } |
| |
| return (ChannelGroup) ehDst.getEntity(); |
| } |
| |
| /** |
| * Copy the MDM catalog. |
| */ |
| public void copyCatalog() { |
| Transaction catTransaction = entityManagerDst.startTransaction(); |
| try { |
| mapSrcDstEntities.clear(); |
| |
| LOG.trace("Exporting Catalog"); |
| // Copy catalog |
| List<CatalogComponent> catComps = new ArrayList<>(); |
| for (ContextType contextType : ContextType.values()) { |
| for (CatalogComponent catComp : entityManagerSrc.loadAll(CatalogComponent.class, contextType)) { |
| LOG.trace("Exporting CatalogComponent '{}'", catComp.getName()); |
| CatalogComponent catCompDst = entityFactoryDst.createCatalogComponent(catComp.getContextType(), |
| catComp.getName()); |
| for (CatalogAttribute catAttr : catComp.getCatalogAttributes()) { |
| if (catAttr.getValueType().isEnumerationType()) { |
| entityFactoryDst.createCatalogAttribute(catAttr.getName(), catAttr.getEnumerationObject(), |
| catCompDst); |
| } else { |
| entityFactoryDst.createCatalogAttribute(catAttr.getName(), catAttr.getValueType(), |
| catCompDst); |
| } |
| } |
| |
| for (CatalogSensor catSensor : catComp.getCatalogSensors()) { |
| LOG.trace("Exporting CatalogSensor '{}'", catComp.getName()); |
| CatalogSensor catSensorDst = entityFactoryDst.createCatalogSensor(catSensor.getName(), |
| catCompDst); |
| for (CatalogAttribute catAttr : catSensor.getCatalogAttributes()) { |
| entityFactoryDst.createCatalogSensorAttribute(catAttr.getName(), catAttr.getValueType(), |
| catSensorDst); |
| } |
| } |
| |
| catComps.add(catCompDst); |
| } |
| } |
| |
| catTransaction.create(catComps); |
| catTransaction.commit(); |
| } catch (Exception exc) { |
| try { |
| catTransaction.abort(); |
| } catch (Exception exc2) { |
| LOG.error("Could not abort transaction!"); |
| } |
| |
| throw new ApiCopyException("Could not copy data.", exc); |
| } |
| } |
| |
| } |