blob: d939073f850b1e486e2c211643de2d9fd3deeef1 [file] [log] [blame]
/********************************************************************************
* 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.api.odsadapter.transaction;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.asam.ods.AoException;
import org.asam.ods.ApplElemAccess;
import org.asam.ods.Blob;
import org.asam.ods.DataType;
import org.asam.ods.ElemId;
import org.asam.ods.NameValueSeqUnit;
import org.asam.ods.SetType;
import org.asam.ods.TS_UnionSeq;
import org.asam.ods.TS_ValueSeq;
import org.asam.ods.T_DCOMPLEX;
import org.asam.ods.T_ExternalReference;
import org.asam.ods.T_LONGLONG;
import org.asam.ods.ValueMatrix;
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.ScalarType;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.dflt.EntityManager;
import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
/**
* Appends values to existing measured values.
*
* @author Alexander Knoblauch, Peak Solution GmbH
*/
public final class AppendMeasuredValuesHandler {
// ======================================================================
// Instance variables
// ======================================================================
private final ODSEntityType submatrixEntityType;
private final ODSTransaction transaction;
private List<WriteRequest> writeRequests = new ArrayList<>();
// ======================================================================
// Constructors
// ======================================================================
/**
* Constructor.
*
* @param transaction The owning {@link ODSTransaction}.
*/
public AppendMeasuredValuesHandler(ODSTransaction transaction) {
this.transaction = transaction;
submatrixEntityType = (ODSEntityType) transaction.getModelManager().getEntityType("SubMatrix");
}
// ======================================================================
// Public methods
// ======================================================================
/**
* Adds given {@link WriteRequest} to be processed.
*
* @param writeRequest The {@code WriteRequest}.
*/
public void addRequest(WriteRequest writeRequest) {
writeRequests.add(writeRequest);
}
/**
* Appends measured values to existing columns from registered
* {@link WriteRequest}s
*
* @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 {
Map<String, List<WriteRequest>> channelGroupToWriteRequests = getChannelGroupToWriteRequests(writeRequests);
channelGroupToWriteRequests.forEach((channelGroupId, writeRequests) -> {
try {
List<NameValueSeqUnit> valuesToAppend = getValuesToAppend(channelGroupId, writeRequests);
appendToChannelGroup(channelGroupId, valuesToAppend);
} catch (AoException e) {
throw new DataAccessException(e.getLocalizedMessage());
}
});
this.writeRequests.clear();
}
// ======================================================================
// Private methods
// ======================================================================
/**
* Generate a map, where the registered {@link WriteRequest}s are mapped to the
* channel group id
*
* @param writeRequests
* @return
*/
private Map<String, List<WriteRequest>> getChannelGroupToWriteRequests(List<WriteRequest> writeRequests) {
Map<String, List<WriteRequest>> returnVal = new HashMap<>();
Map<String, List<Channel>> channelMap = new HashMap<>();
EntityManager em = transaction.getContext().getEntityManager().get();
writeRequests.forEach(wr -> {
List<WriteRequest> list = returnVal.computeIfAbsent(wr.getChannelGroup().getID(), v -> new ArrayList<>());
list.add(wr);
channelMap.computeIfAbsent(wr.getChannelGroup().getID(),
v -> em.loadChildren(wr.getChannelGroup(), Channel.class));
});
return returnVal;
}
/**
* Getting all values to append as {@link NameValueSeqUnit} for the specific
* channelgroup id
*
* @param channelGroupId unique id of a channelgroup
* @param writeRequests {@link WriteRequest}s
* @return
*/
private List<NameValueSeqUnit> getValuesToAppend(String channelGroupId, List<WriteRequest> writeRequests) {
List<NameValueSeqUnit> returnVal = new ArrayList<>();
writeRequests.forEach(wr -> returnVal.add(getChannelValuesToAppend(wr.getChannel(), wr.getValues(), 0)));
int maxLength = getMaxLength(returnVal);
returnVal.forEach(nvusu -> {
if (maxLength > nvusu.value.flag.length) {
fillNameValueSeqUnit(nvusu, maxLength);
}
});
EntityManager em = transaction.getContext().getEntityManager().get();
ChannelGroup channelGroup = em.load(ChannelGroup.class, channelGroupId);
List<Channel> channels = em.loadChildren(channelGroup, Channel.class);
channels.forEach(c -> {
if (!isChannelinValueSeq(returnVal, c)) {
returnVal.add(getChannelValuesToAppend(c, null, maxLength));
}
});
return returnVal;
}
/**
* Check if a {@link NameValueSeqUnit} for the channel exists in the list
*
* @param valueSeq
* @param channel
* @return true if exists, otherwise false
*/
private boolean isChannelinValueSeq(List<NameValueSeqUnit> valueSeq, Channel channel) {
boolean isChannelinValueSeq = false;
String channelName = channel.getName();
for (NameValueSeqUnit nvsu : valueSeq) {
if (nvsu.valName.equals(channelName)) {
isChannelinValueSeq = true;
break;
}
}
return isChannelinValueSeq;
}
/**
* Fills the {@link NameValueSeqUnit} with invalid values, if the given length
* is higher then the length of the {@link NameValueSeqUnit}
*
* @param nvsu
* @param length
*/
private void fillNameValueSeqUnit(NameValueSeqUnit nvsu, int length) {
nvsu.value.flag = Arrays.copyOf(nvsu.value.flag, length);
DataType dataType = nvsu.value.u.discriminator();
if (DataType.DT_FLOAT.equals(dataType)) {
nvsu.value.u.floatVal(Arrays.copyOf(nvsu.value.u.floatVal(), length));
} else if (DataType.DT_BLOB.equals(dataType)) {
nvsu.value.u.blobVal(Arrays.copyOf(nvsu.value.u.blobVal(), length));
} else if (DataType.DT_BOOLEAN.equals(dataType)) {
nvsu.value.u.booleanVal(Arrays.copyOf(nvsu.value.u.booleanVal(), length));
} else if (DataType.DT_BYTE.equals(dataType)) {
nvsu.value.u.byteVal(Arrays.copyOf(nvsu.value.u.byteVal(), length));
} else if (DataType.DT_BYTESTR.equals(dataType)) {
nvsu.value.u.bytestrVal(Arrays.copyOf(nvsu.value.u.bytestrVal(), length));
} else if (DataType.DT_COMPLEX.equals(dataType)) {
nvsu.value.u.complexVal(Arrays.copyOf(nvsu.value.u.complexVal(), length));
} else if (DataType.DT_DATE.equals(dataType)) {
nvsu.value.u.dateVal(Arrays.copyOf(nvsu.value.u.dateVal(), length));
} else if (DataType.DT_DCOMPLEX.equals(dataType)) {
nvsu.value.u.dcomplexVal(Arrays.copyOf(nvsu.value.u.dcomplexVal(), length));
} else if (DataType.DT_DOUBLE.equals(dataType)) {
nvsu.value.u.doubleVal(Arrays.copyOf(nvsu.value.u.doubleVal(), length));
} else if (DataType.DT_EXTERNALREFERENCE.equals(dataType)) {
nvsu.value.u.extRefVal(Arrays.copyOf(nvsu.value.u.extRefVal(), length));
} else if (DataType.DT_LONG.equals(dataType)) {
nvsu.value.u.longVal(Arrays.copyOf(nvsu.value.u.longVal(), length));
} else if (DataType.DT_LONGLONG.equals(dataType)) {
nvsu.value.u.longlongVal(Arrays.copyOf(nvsu.value.u.longlongVal(), length));
} else if (DataType.DT_SHORT.equals(dataType)) {
nvsu.value.u.shortVal(Arrays.copyOf(nvsu.value.u.shortVal(), length));
} else if (DataType.DT_STRING.equals(dataType)) {
nvsu.value.u.stringVal(Arrays.copyOf(nvsu.value.u.stringVal(), length));
} else {
new DataAccessException("Not supported Datatype: " + dataType);
}
}
/**
*
* @param valSeq
* @return
*/
private int getMaxLength(List<NameValueSeqUnit> valSeq) {
int maxLength = 0;
for (NameValueSeqUnit nvsu : valSeq) {
if (nvsu.value.flag.length > maxLength) {
maxLength = nvsu.value.flag.length;
}
}
return maxLength;
}
/**
* Appending the ValuesToAppend to the value matrix
*
* @param channelGroupId
* @param valuesToAppend
* @throws AoException
*/
private void appendToChannelGroup(String channelGroupId, List<NameValueSeqUnit> valuesToAppend) throws AoException {
T_LONGLONG aIDSubMatrix = submatrixEntityType.getODSID();
ValueMatrix valueMatrix = getApplElemAccess()
.getValueMatrix(new ElemId(aIDSubMatrix, ODSConverter.toODSID(channelGroupId)));
valueMatrix.setValue(SetType.APPEND, valueMatrix.getRowCount(),
valuesToAppend.toArray(new NameValueSeqUnit[valuesToAppend.size()]));
}
/**
* Converting the values to a {@link NameValueSeqUnit}, if values are null the
* {@link NameValueSeqUnit} will contains only invalid values
*
* @param channel {@link Channel}
* @param values to convert
* @param length of the {@link NameValueSeqUnit}
* @return
*/
private NameValueSeqUnit getChannelValuesToAppend(Channel channel, Object values, int length) {
NameValueSeqUnit nvsu = new NameValueSeqUnit();
String unitName = channel.getUnit().getName();
nvsu.valName = channel.getName();
nvsu.unit = unitName;
nvsu.value = new TS_ValueSeq();
if (ScalarType.FLOAT.equals(channel.getScalarType())) {
float[] vals = new float[length];
if (values != null) {
vals = (float[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.floatVal(vals);
} else if (ScalarType.INTEGER.equals(channel.getScalarType())) {
int[] vals = new int[length];
if (values != null) {
vals = (int[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.longVal(vals);
} else if (ScalarType.BLOB.equals(channel.getScalarType())) {
Blob[] vals = new Blob[length];
if (values != null) {
vals = (Blob[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.blobVal(vals);
} else if (ScalarType.BOOLEAN.equals(channel.getScalarType())) {
boolean[] vals = new boolean[length];
if (values != null) {
vals = (boolean[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.booleanVal(vals);
} else if (ScalarType.BYTE.equals(channel.getScalarType())) {
byte[] vals = new byte[length];
if (values != null) {
vals = (byte[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.byteVal(vals);
} else if (ScalarType.DATE.equals(channel.getScalarType())) {
String[] vals = new String[length];
if (values != null) {
vals = (String[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.dateVal(vals);
} else if (ScalarType.DOUBLE.equals(channel.getScalarType())) {
double[] vals = new double[length];
if (values != null) {
vals = (double[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.doubleVal(vals);
} else if (ScalarType.DOUBLE_COMPLEX.equals(channel.getScalarType())) {
T_DCOMPLEX[] vals = new T_DCOMPLEX[length];
if (values != null) {
vals = (T_DCOMPLEX[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.dcomplexVal(vals);
} else if (ScalarType.FILE_LINK.equals(channel.getScalarType())) {
T_ExternalReference[] vals = new T_ExternalReference[length];
if (values != null) {
vals = (T_ExternalReference[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.extRefVal(vals);
} else if (ScalarType.LONG.equals(channel.getScalarType())) {
T_LONGLONG[] vals = new T_LONGLONG[length];
if (values != null) {
vals = (T_LONGLONG[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.longlongVal(vals);
} else if (ScalarType.SHORT.equals(channel.getScalarType())) {
short[] vals = new short[length];
if (values != null) {
vals = (short[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.shortVal(vals);
} else if (ScalarType.STRING.equals(channel.getScalarType())) {
String[] vals = new String[length];
if (values != null) {
vals = (String[]) values;
}
nvsu.value.flag = new short[vals.length];
nvsu.value.u = new TS_UnionSeq();
nvsu.value.u.stringVal(vals);
} else {
throw new DataAccessException("Not supported DataType " + values.getClass());
}
if (values != null) {
Arrays.fill(nvsu.value.flag, (short) 15);
}
return nvsu;
}
/**
* Returns the {@link ApplElemAccess}.
*
* @return The {@code ApplElemAccess} is returned.
* @throws AoException Thrown in case of errors.
*/
private ApplElemAccess getApplElemAccess() throws AoException {
return transaction.getContext().getODSModelManager().getApplElemAccess();
}
}