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