| /******************************************************************************** |
| * 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); |
| } |
| |
| } |