blob: 11af7d457414c1485b1d8693314e6b318a1d8c40 [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.api.atfxadapter.transaction;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import org.asam.ods.AoException;
import org.eclipse.mdm.api.base.adapter.Attribute;
import org.eclipse.mdm.api.base.adapter.Core;
import org.eclipse.mdm.api.base.adapter.DefaultCore;
import org.eclipse.mdm.api.base.adapter.EntityType;
import org.eclipse.mdm.api.base.massdata.ExternalComponent;
import org.eclipse.mdm.api.base.massdata.ExternalComponentEntity;
import org.eclipse.mdm.api.base.massdata.WriteRequest;
import org.eclipse.mdm.api.base.model.BaseEntity;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.MimeType;
import org.eclipse.mdm.api.base.model.Value;
import org.eclipse.mdm.api.base.model.ValueType;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
/**
* Writes mass data specified in {@link WriteRequest}s.
*
* @see org.eclipse.mdm.api.odsadapter.transaction.WriteRequestHandler
*/
public final class WriteRequestHandler {
private static final String AE_LC_ATTR_INDEPENDENT = "IndependentFlag";
private static final String AE_LC_ATTR_REPRESENTATION = "SequenceRepresentation";
private static final String AE_LC_ATTR_PARAMETERS = "GenerationParameters";
private static final String AE_LC_ATTR_RAWDATATYPE = "RawDatatype";
private static final String AE_LC_ATTR_AXISTYPE = "axistype";
private static final String AE_LC_ATTR_VALUES = "Values";
private static final String AE_LC_ATTR_FLAGS = "Flags";
private static final String AE_LC_ATTR_GLOBAL_FLAG = "GlobalFlag";
private static final String AE_EC_ATTR_BITCOUNT = "BitCount";
private static final String AE_EC_ATTR_BITOFFSET = "BitOffset";
private final List<Core> cores = new ArrayList<>();
private final EntityType localColumnEntityType;
private final InsertStatement insertStatement;
/**
* Constructor.
*
* @param transaction The owning {@link ATFXTransaction}.
*/
public WriteRequestHandler(ATFXTransaction transaction) {
localColumnEntityType = transaction.getModelManager().getEntityType("LocalColumn");
insertStatement = new InsertStatement(transaction, localColumnEntityType);
}
/**
* Adds given {@link WriteRequest} to be processed.
*
* @param writeRequest The {@code WriteRequest}.
*/
public void addRequest(WriteRequest writeRequest) {
cores.add(createCore(writeRequest));
}
/**
* Imports given mass data configurations.
*
* @throws AoException Thrown if the execution fails.
* @throws DataAccessException Thrown if the execution fails.
* @throws IOException Thrown if a file transfer operation fails.
*/
public void execute() throws AoException, DataAccessException, IOException {
insertStatement.executeWithCores(cores);
}
/**
* Reads given {@link WriteRequest} and prepares a corresponding {@link Core}
* for import.
*
* @param writeRequest The mass data configuration.
* @return The created {@code Core} is returned.
*/
private Core createCore(WriteRequest writeRequest) {
Core core = new DefaultCore(localColumnEntityType);
core.getPermanentStore().set(writeRequest.getChannelGroup());
core.getMutableStore().set(writeRequest.getChannel());
Map<String, Value> values = core.getValues();
values.get(Entity.ATTR_NAME).set(writeRequest.getChannel().getName());
values.get(Entity.ATTR_MIMETYPE).set("application/x-asam.aolocalcolumn");
values.get(AE_LC_ATTR_INDEPENDENT).set((short) (writeRequest.isIndependent() ? 1 : 0));
values.get(AE_LC_ATTR_RAWDATATYPE).set(writeRequest.getRawScalarType());
values.get(AE_LC_ATTR_REPRESENTATION).set(writeRequest.getSequenceRepresentation());
values.get(AE_LC_ATTR_AXISTYPE).set(writeRequest.getAxisType());
values.get(AE_LC_ATTR_PARAMETERS).set(writeRequest.getGenerationParameters());
ValueType<?> valueType = writeRequest.getRawScalarType().toValueType();
if (writeRequest.hasValues()) {
String unitName = writeRequest.getChannel().getUnit().getName();
values.put(AE_LC_ATTR_VALUES,
valueType.create(AE_LC_ATTR_VALUES, unitName, true, writeRequest.getValues()));
// OpenATFX issue: For "implicit" columns, if no value for the
// GenerationParameters attribute is present,
// it is attempted to transfer the local column values (through which the
// generation parameters are
// available in these cases) to the GenerationParameters attribute without
// converting them to the
// correct DS_DOUBLE data type first (unless it is a DOUBLE or LONG column),
// resulting in an exception.
// Hence, supply correctly converted generation parameters as a workaround:
if (writeRequest.getSequenceRepresentation().isImplicit()) {
Object genParamValues = writeRequest.getValues();
double[] genParamD = new double[Array.getLength(genParamValues)];
IntStream.range(0, genParamD.length)
.forEach(i -> genParamD[i] = ((Number) Array.get(genParamValues, i)).doubleValue());
values.get(AE_LC_ATTR_PARAMETERS).set(genParamD);
// remove GenerationParameters from Values
values.put(AE_LC_ATTR_VALUES, valueType.create(AE_LC_ATTR_VALUES));
}
// flags
if (writeRequest.areAllValid()) {
values.get(AE_LC_ATTR_GLOBAL_FLAG).set((short) 15);
} else {
short[] flags = ODSConverter.toODSValidFlagSeq(writeRequest.getFlags());
values.get(AE_LC_ATTR_FLAGS).set(flags);
}
} else if (writeRequest.hasExternalComponents()) {
// No values to write (ext comps are used instead), but we have to set the
// Values attribute to empty/invalid, based on the rawDataType
values.put(AE_LC_ATTR_VALUES, valueType.create(AE_LC_ATTR_VALUES));
// Set global flag as specified in the WriteRequest:
values.get(AE_LC_ATTR_GLOBAL_FLAG).set(writeRequest.getGlobalFlag());
EntityType externalComponentEntityType = insertStatement.getTransaction().getModelManager()
.getEntityType("ExternalComponent");
List<Attribute> listAttrsExtComp = externalComponentEntityType.getAttributes();
boolean hasMimeType = (listAttrsExtComp.stream().filter(a -> Entity.ATTR_MIMETYPE.equals(a.getName()))
.count() > 0);
boolean hasBitCount = (listAttrsExtComp.stream().filter(a -> AE_EC_ATTR_BITCOUNT.equals(a.getName()))
.count() > 0);
boolean hasBitOffset = (listAttrsExtComp.stream().filter(a -> AE_EC_ATTR_BITOFFSET.equals(a.getName()))
.count() > 0);
int ordinalNumber = 1;
for (ExternalComponent extComp : writeRequest.getExternalComponents()) {
Core extCompCore = new DefaultCore(externalComponentEntityType);
ExternalComponentEntity extCompEntity = new ExternalComponentEntity(extCompCore);
extCompEntity.setName(writeRequest.getChannel().getName());
if (hasMimeType) {
extCompEntity.setMimeType(new MimeType("application/x-asam.aoexternalcomponent"));
}
extCompEntity.setTypeSpecification(extComp.getTypeSpecification());
extCompEntity.setLength(extComp.getLength());
extCompEntity.setStartOffset(extComp.getStartOffset());
extCompEntity.setBlocksize(extComp.getBlocksize());
extCompEntity.setValuesPerBlock(extComp.getValuesPerBlock());
extCompEntity.setValueOffset(extComp.getValueOffset());
extCompEntity.setFileLink(extComp.getFileLink());
extCompEntity.setFlagsFileLink(extComp.getFlagsFileLink());
extCompEntity.setFlagsStartOffset(extComp.getFlagsStartOffset());
extCompEntity.setOrdinalNumber(ordinalNumber++);
if (hasBitCount) {
extCompEntity.setBitCount(extComp.getBitCount());
}
if (hasBitOffset) {
extCompEntity.setBitOffset(extComp.getBitOffset());
}
core.getChildrenStore().add(extCompEntity);
extCompCore.getPermanentStore().set(new BaseEntity(core) {
});
}
} else {
throw new IllegalStateException("Given write request neither has measured values nor external components");
}
return core;
}
}