blob: 9a99d08034837c6db72e75f1b18e609f32f13fb2 [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.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
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.ServiceNotProvidedException;
import org.eclipse.mdm.api.base.Transaction;
import org.eclipse.mdm.api.base.adapter.ModelManager;
import org.eclipse.mdm.api.base.massdata.AnyTypeValuesBuilder;
import org.eclipse.mdm.api.base.massdata.ComplexNumericalValuesBuilder;
import org.eclipse.mdm.api.base.massdata.NumericalValuesBuilder;
import org.eclipse.mdm.api.base.massdata.WriteRequest;
import org.eclipse.mdm.api.base.massdata.WriteRequestBuilder;
import org.eclipse.mdm.api.base.model.Channel;
import org.eclipse.mdm.api.base.model.ChannelGroup;
import org.eclipse.mdm.api.base.model.DoubleComplex;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.FileLink;
import org.eclipse.mdm.api.base.model.FloatComplex;
import org.eclipse.mdm.api.base.model.MeasuredValues;
import org.eclipse.mdm.api.base.model.MeasuredValues.ValueIterator;
import org.eclipse.mdm.api.base.model.Measurement;
import org.eclipse.mdm.api.base.model.ScalarType;
import org.eclipse.mdm.api.base.model.SequenceRepresentation;
import org.eclipse.mdm.api.base.model.Test;
import org.eclipse.mdm.api.base.model.TestStep;
import org.eclipse.mdm.api.base.model.Value;
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.EntityFactory;
import org.eclipse.mdm.api.dflt.model.Pool;
import org.eclipse.mdm.api.dflt.model.Project;
import com.google.common.base.Strings;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
public abstract class AtfxTransferBase {
List<Class<? extends Entity>> supportedRootEntities = Arrays.asList(Project.class, Pool.class, Test.class,
TestStep.class, Measurement.class);
ApplicationContext contextSrc;
EntityManager entityManagerSrc;
ApplicationContext contextDst;
EntityManager entityManagerDst;
EntityFactory entityFactoryDst;
ModelManager modelManagerDst;
Map<EntityHolder, EntityHolder> mapSrcDstEntities = new HashMap<>();
public AtfxTransferBase(ApplicationContext src, ApplicationContext dst) {
contextSrc = src;
entityManagerSrc = contextSrc.getEntityManager()
.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
contextDst = dst;
entityManagerDst = contextDst.getEntityManager()
.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
entityFactoryDst = contextDst.getEntityFactory()
.orElseThrow(() -> new ServiceNotProvidedException(EntityFactory.class));
modelManagerDst = contextDst.getModelManager()
.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
}
ListMultimap<Class<? extends Entity>, Entity> loadParents(List<? extends Entity> entities) {
List<Entity> list = entities.stream().filter(e -> !isSupported(e)).collect(Collectors.toList());
if (!list.isEmpty()) {
throw new ApiCopyException("Entity " + list + " not supported!");
}
LinkedListMultimap<Class<? extends Entity>, Entity> byType = LinkedListMultimap.create();
entities.forEach(e -> byType.put(e.getClass(), e));
byType.get(Measurement.class)
.forEach(e -> byType.put(TestStep.class, entityManagerSrc.loadParent(e, TestStep.class).get()));
byType.get(TestStep.class)
.forEach(e -> byType.put(Test.class, entityManagerSrc.loadParent(e, Test.class).get()));
byType.get(Test.class).forEach(e -> byType.put(Pool.class, entityManagerSrc.loadParent(e, Pool.class).get()));
byType.get(Pool.class)
.forEach(e -> byType.put(Project.class, entityManagerSrc.loadParent(e, Project.class).get()));
entities.forEach(e -> byType.remove(e.getClass(), e));
return byType;
}
boolean isSupported(Entity e) {
return supportedRootEntities.contains(e.getClass());
}
<T extends Entity> Optional<T> fetchOne(SearchService searchService, Class<T> entityClass, Filter filter) {
List<T> results = searchService.fetch(entityClass, filter);
if (results.isEmpty()) {
return Optional.empty();
} else if (results.size() == 1) {
return Optional.of(results.get(0));
} else {
throw new IllegalStateException(String.format("Expected at most one instance of %s, but found %s!",
entityClass.getName(), results.size()));
}
}
<T extends Entity> Optional<T> fetchOne(EntityManager entityManager, Class<T> entityClass, String name) {
List<T> results = entityManager.loadAll(entityClass).stream().filter(entity -> entity.getName().equals(name))
.collect(Collectors.toList());
if (results.isEmpty()) {
return Optional.empty();
} else if (results.size() == 1) {
return Optional.of(results.get(0));
} else {
throw new IllegalStateException(String.format("Expected at most one instance of %s, but found %s!",
entityClass.getName(), results.size()));
}
}
boolean isNewEntity(Entity entity) {
return (Strings.isNullOrEmpty(entity.getID()) || Long.valueOf(entity.getID()) <= 0);
}
void persist(Transaction transaction, Entity entity) {
if (isNewEntity(entity)) {
transaction.create(Lists.newArrayList(entity));
} else {
transaction.update(Lists.newArrayList(entity));
}
}
void copyValues(Entity srcEntity, Entity dstEntity, List<String> ignoredAttributes) {
Set<String> valueNamesDst = dstEntity.getValues().keySet();
for (Map.Entry<String, Value> me : srcEntity.getValues().entrySet()) {
String key = me.getKey();
if (!ignoredAttributes.contains(key) && valueNamesDst.contains(key)) {
dstEntity.getValue(me.getKey()).set(me.getValue().extract());
}
}
}
WriteRequest createWriteRequest(ChannelGroup channelGroupDst, Channel channelDst, MeasuredValues measuredValues) {
WriteRequestBuilder wrb = WriteRequest.create(channelGroupDst, channelDst, measuredValues.getAxisType());
NumericalValuesBuilder builder = null;
SequenceRepresentation seqRep = measuredValues.getSequenceRepresentation();
ScalarType scalarType = measuredValues.getScalarType();
boolean independent = measuredValues.isIndependent();
double[] generationParameters = measuredValues.getGenerationParameters();
if (SequenceRepresentation.EXPLICIT.equals(seqRep) || SequenceRepresentation.EXPLICIT_EXTERNAL.equals(seqRep)) {
builder = wrb.explicit();
} else if (SequenceRepresentation.IMPLICIT_CONSTANT.equals(seqRep)) {
checkGenerationParameters(generationParameters, 1);
return wrb.implicitConstant(scalarType, generationParameters[0]).build();
} else if (SequenceRepresentation.IMPLICIT_LINEAR.equals(seqRep)) {
checkGenerationParameters(generationParameters, 2);
return wrb.implicitLinear(scalarType, generationParameters[0], generationParameters[1])
.independent(independent).build();
} else if (SequenceRepresentation.IMPLICIT_SAW.equals(seqRep)) {
checkGenerationParameters(generationParameters, 3);
return wrb
.implicitSaw(scalarType, generationParameters[0], generationParameters[1], generationParameters[2])
.build();
} else if (SequenceRepresentation.RAW_LINEAR.equals(seqRep)
|| SequenceRepresentation.RAW_LINEAR_EXTERNAL.equals(seqRep)) {
checkGenerationParameters(generationParameters, 2);
builder = wrb.rawLinear(generationParameters[0], generationParameters[1]);
} else if (SequenceRepresentation.RAW_LINEAR_CALIBRATED.equals(seqRep)
|| SequenceRepresentation.RAW_LINEAR_CALIBRATED_EXTERNAL.equals(seqRep)) {
checkGenerationParameters(generationParameters, 3);
builder = wrb.rawLinearCalibrated(generationParameters[0], generationParameters[1],
generationParameters[2]);
} else if (SequenceRepresentation.RAW_POLYNOMIAL.equals(seqRep)
|| SequenceRepresentation.RAW_POLYNOMIAL_EXTERNAL.equals(seqRep)) {
builder = wrb.rawPolynomial(generationParameters);
}
if (scalarType.isString()) {
String[] values = new String[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<String> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return castBuilder(builder, AnyTypeValuesBuilder.class).stringValues(values, flags).build();
} else if (scalarType.isDate()) {
LocalDateTime[] values = new LocalDateTime[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<LocalDateTime> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return castBuilder(builder, AnyTypeValuesBuilder.class).dateValues(values, flags).independent(independent)
.build();
} else if (scalarType.isBoolean()) {
boolean[] values = new boolean[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<Boolean> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return castBuilder(builder, AnyTypeValuesBuilder.class).booleanValues(values, flags).build();
} else if (scalarType.isByte()) {
byte[] values = new byte[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<Byte> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return builder.byteValues(values, flags).independent(independent).build();
} else if (scalarType.isShort()) {
short[] values = new short[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<Short> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return builder.shortValues(values, flags).independent(independent).build();
} else if (scalarType.isInteger()) {
int[] values = new int[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<Integer> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return builder.integerValues(values, flags).independent(independent).build();
} else if (scalarType.isLong()) {
long[] values = new long[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<Long> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return builder.longValues(values, flags).independent(independent).build();
} else if (scalarType.isFloat()) {
float[] values = new float[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<Float> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return builder.floatValues(values, flags).independent(independent).build();
} else if (scalarType.isDouble()) {
double[] values = new double[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<Double> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return builder.doubleValues(values, flags).independent(independent).build();
} else if (scalarType.isByteStream()) {
byte[][] values = new byte[measuredValues.getLength()][];
boolean[] flags = new boolean[values.length];
ValueIterator<byte[]> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return castBuilder(builder, AnyTypeValuesBuilder.class).byteStreamValues(values, flags).build();
} else if (scalarType.isFloatComplex()) {
FloatComplex[] values = new FloatComplex[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<FloatComplex> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return castBuilder(builder, ComplexNumericalValuesBuilder.class).floatComplexValues(values, flags).build();
} else if (scalarType.isDoubleComplex()) {
DoubleComplex[] values = new DoubleComplex[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<DoubleComplex> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return castBuilder(builder, ComplexNumericalValuesBuilder.class).doubleComplexValues(values, flags).build();
} else if (scalarType.isFileLink()) {
FileLink[] values = new FileLink[measuredValues.getLength()];
boolean[] flags = new boolean[values.length];
ValueIterator<FileLink> iter = measuredValues.iterator();
int count = 0;
while (iter.hasNext()) {
flags[count] = iter.isValid();
values[count++] = iter.next();
}
return castBuilder(builder, AnyTypeValuesBuilder.class).fileLinkValues(values, flags).build();
} else if (scalarType.isBlob()) {
Object value = null;
ValueIterator<Object> iter = measuredValues.iterator();
while (iter.hasNext()) {
value = iter.next();
}
return castBuilder(builder, AnyTypeValuesBuilder.class).blobValue(value).build();
} else {
throw new IllegalStateException(
String.format("Unsupported ScalarType %s in MeasuredValues!", scalarType.name()));
}
}
void checkGenerationParameters(double[] generationParameters, int expectedLength) {
if (null == generationParameters || generationParameters.length < expectedLength) {
throw new IllegalStateException(String.format("Number of generation parameters is %d, expected %d!",
(null == generationParameters ? 0 : generationParameters.length), expectedLength));
}
}
<T extends NumericalValuesBuilder> T castBuilder(NumericalValuesBuilder builder, Class<T> cls) {
if (!cls.isInstance(builder)) {
throw new IllegalStateException(String.format(
"Error creating the write values builder, expected class is %s, actual class is %s (likely column data type and sequence representation mismatch)!",
cls.getName(), (null == builder ? "???" : builder.getClass().getName())));
}
return cls.cast(builder);
}
}