added support for array composition and several improvements
- implemented CABLOCK
- only array composition at CNBLOCKs is supported yet, no
structure-based composition
- when a CABLOCK is linked via the composition link from a CNBLOCK, the
resulting AoMeasurementQuantity in ODS will have specified the rank and
dimension attributes accordingly, as specified by the ODS standard
- an additional attribute ('columnOriented' of type boolean at
AoMeasurementQuantity) is also set, containing the information, whether
the channel's value tensor has to be interpreted in a row- or
column-oriented manner, when calculating the actual values from it
- support for half-precision floating point data type
- fixed local column creation: independent and axistype are now set
according to SyncType and not ChannelType
- added BlockReferenceTriple for handling of according references in mdf
files
- fixed misleading names of fields in CABLOCK
- support default values at scale conversions with CCBLOCKS
Signed-off-by: Markus Renner <m.renner@peak-solution.de>
diff --git a/README.md b/README.md
index de19ee0..fc3a110 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,6 @@
- hd_ch_first must be 0 (channel hierarchy not yet supported)
- hd_flags must be 0 [bits 00] (start angle value below is invalid, start distance value below is invalid)
* CHBLOCK (MDF3): not yet supported, will be ignored with warning
-* CABLOCK (MDF4): not yet supported, will be ignored with warning
* ATBLOCK: not yet supported, will be ignored with warning
* EVBLOCK:
- ev_ev_parent will be ignored with warning
@@ -62,7 +61,7 @@
- cg_flags must be null (VLSD and bus events not supported), otherwise an exception is thrown
- cg_inval_bytes must be null (invalidation bits not supported), otherwise an exception is thrown
* CNBLOCK
- - cn_composition must be null (composition not supported), otherwise an exception is thrown
+ - cn_composition only array composition supported, otherwise an exception is thrown
- cn_at_reference: not yet supported, will be ignored with warning
- cn_limit_min: not yet supported, will be ignored with warning
- cn_limit_max: not yet supported, will be ignored with warning
diff --git a/build.gradle b/build.gradle
index 176aa07..be1125f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -19,7 +19,8 @@
description = 'OpenATFX MDF driver'
group = 'org.eclipse.mdm'
-version = '1.2.0'
+version = '1.3.0'
+def atfxVersion = '0.8.8'
apply plugin: 'java'
apply plugin: 'eclipse'
@@ -29,7 +30,7 @@
dependencies {
// openATFX
- compile fileTree(dir: 'build/openatfx-0.6.4/lib', include: '*.jar')
+ compile fileTree(dir: "${buildDir}/openatfx-${atfxVersion}/lib", include: '*.jar')
// testing
testCompile 'junit:junit:4.12'
@@ -40,20 +41,18 @@
task downloadOpenATFX(type: Download) {
acceptAnyCertificate true
overwrite false
- // use mirror subdomain of 'https://sourceforge.net/projects/openatfx/files/openatfx-0.6.4-jars.zip/download'
- // because gradle has problems establishing a ssl connection with sourceforge directly
- src 'https://10gbps-io.dl.sourceforge.net/project/openatfx/openatfx-0.6.4-jars.zip'
- dest new File(buildDir, 'openatfx-0.6.4-jars.zip')
+ src "https://sourceforge.net/projects/openatfx/files/openatfx-${atfxVersion}-jars.zip/download"
+ dest file("${buildDir}/openatfx-${atfxVersion}-jars.zip")
outputs.file dest
}
task unzipOpenATFX(dependsOn: downloadOpenATFX, type: Copy) {
from zipTree(downloadOpenATFX.dest)
into buildDir
- outputs.dir new File(buildDir, 'openatfx-0.6.4')
+ outputs.dir file("${buildDir}/openatfx-${atfxVersion}")
}
-//compileJava.dependsOn unzipOpenATFX
+compileJava.dependsOn unzipOpenATFX
tasks.withType(JavaCompile) {
sourceCompatibility = '1.8'
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2cfaf45..ff6b478 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/AoSessionWriter.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/AoSessionWriter.java
index e8d8347..810ef31 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/AoSessionWriter.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/AoSessionWriter.java
@@ -112,6 +112,8 @@
private boolean attachLinks2Tsts = false;
private boolean copyToSub = false;
private boolean ignoreATBLOCKs = false;
+
+ private Map<Long, Long> arraySubMatrixIDsByNrOfValues = new HashMap<>();
/**
* Constructor.
@@ -283,11 +285,14 @@
ODSInsertStatement ins = new ODSInsertStatement(modelCache, "mea");
+ String mrName = null;
if (useFileNameAsResultName) {
- ins.setStringVal("iname", FileUtil.getResultName(fileName.toString(), resultSuffix));
+ mrName = FileUtil.getResultName(fileName.toString(), resultSuffix);
} else {
- ins.setStringVal("iname", resultName + resultSuffix);
+ mrName = resultName + resultSuffix;
}
+ ins.setStringVal("iname", mrName);
+ LOG.debug("MeaResult name: " + mrName);
ins.setStringVal("mt", resultMimeType);
if (addMDF3FileAsResultAttachment) {
@@ -530,8 +535,11 @@
// create SubMatrix instance
ODSInsertStatement ins = new ODSInsertStatement(modelCache, "sm");
- ins.setStringVal("iname", "sm_" + countFormat.format(grpNo));
+ String smName = "sm_" + countFormat.format(grpNo);
+ ins.setStringVal("iname", smName);
+ LOG.debug("SubMatrix name: " + smName);
+
// write CGComment
BLOCK mdblock = cgBlock.getMdCommentBlock();
if (mdblock != null) {
@@ -619,7 +627,8 @@
// iterate over channel blocks
CNBLOCK cnBlock = cgBlock.getCnFirstBlock();
while (cnBlock != null) {
-
+ LOG.debug("CNBLOCK=" + cnBlock);
+
if ((cnBlock.getFlags() & 0x02) != 0 && cnBlock.getInvalBitPos() > 0) {
if (writeFlagsFile) {
// NOTE: flags are exported within writeEc()!
@@ -630,14 +639,8 @@
continue;
}
}
- // check invalidation bits (not yet supported)
- if (cnBlock.getLnkComposition() != 0) {
- LOG.warn("Composition of channels not supported! [CNBLOCK=" + cnBlock + "]");
- // throw new IOException("Composition of channels not supported!
- // [CNBLOCK=" + cnBlock + "]");
- }
- // cn_at_reference: attachments TODO
+ // TODO cn_at_reference: attachments
if (cnBlock.getLnkAtReference().length > 0) {
LOG.warn("Found channel 'cn_at_reference'>0, not yet supported ");
}
@@ -650,6 +653,8 @@
meqName = meqName.replaceAll("\\[", "{");
meqName = meqName.replaceAll("\\]", "}");
}
+
+ LOG.debug("Channel name: " + meqName);
// check for duplicate signal names and add suffix (except time
// channel)
@@ -700,15 +705,21 @@
}
}
+ BLOCK compositionBlock = null;
+ if (cnBlock.getLnkComposition() != 0) {
+ LOG.debug("Composition found!");
+ compositionBlock = cnBlock.getCompositionBlock();
+ }
+
// create instance of 'AoMeasurementQuantity' (if not yet existing)
Long iidMeq = meqInstances.get(meqName);
if (iidMeq == null) {
- iidMeq = createMeasurementQuantity(modelCache, cnBlock, ccBlock, meqName, iidMea, null, untInstances);
+ iidMeq = createMeasurementQuantity(modelCache, cnBlock, ccBlock, compositionBlock, meqName, iidMea, null, untInstances);
meqInstances.put(meqName, iidMeq);
}
// create 'AoLocalColumn' instance
- long iidLc = createLocalColumn(modelCache, dgBlock, cgBlock, cnBlock, ccBlock, meqName, iidSm, iidMeq,
+ long iidLc = createLocalColumn(modelCache, dgBlock, cgBlock, cnBlock, ccBlock, compositionBlock, meqName, iidMea, iidSm, iidMeq,
iidPrevSm, null);
// relation to previews
if (iidPrevSm != null) {
@@ -722,7 +733,7 @@
// (6-9) or VLSD-Channel (Type ==1) or virtual master channel (Type == 3))
if (!(cnBlock.getDataType() >= 6 && cnBlock.getDataType() <= 9
|| cnBlock.getChannelType() == 1 || cnBlock.getChannelType() == 3)) {
- writeEc(modelCache, iidLc, idBlock, dgBlock, cgBlock, cnBlock, ccBlock, dgBlock.getLnkData(), 0);
+ writeEc(modelCache, iidLc, idBlock, dgBlock, cgBlock, cnBlock, ccBlock, compositionBlock, dgBlock.getLnkData(), 0);
}
// create Table for Lookup conversion, if conversion type is 4 to 10
@@ -744,7 +755,7 @@
cnBlock = cnBlock.getCnNextBlock();
}
}
-
+
/**
* Create and insert the actual MeasurementQuantity This function also
* creates the corresponding unit if it doesn't already exist.
@@ -755,6 +766,8 @@
* The Channel Block.
* @param ccBlock
* The Conversion Block.
+ * @param compositionBlock
+ * The composition Block, may be null.
* @param meqName
* The Name the Measurement will have.
* @param iidMea
@@ -770,7 +783,7 @@
* If an I/O-error occurs.
* @throws AoException
*/
- long createMeasurementQuantity(ODSModelCache modelCache, CNBLOCK cnBlock, CCBLOCK ccBlock, String meqName,
+ long createMeasurementQuantity(ODSModelCache modelCache, CNBLOCK cnBlock, CCBLOCK ccBlock, BLOCK compositionBlock, String meqName,
long iidMea, String mimeType, Map<String, Long> untInstances) throws IOException, AoException {
int seqRep = getSeqRep(cnBlock, ccBlock);
double[] genParams = getGenerationParameters(ccBlock);
@@ -825,9 +838,98 @@
if (uiid != -1) {
ins.setLongLongVal("unt", uiid);
}
- long iidMeq = ins.execute();
-
- return iidMeq;
+
+ // handle composition block and transform into according MeaQuantity
+ handleCompositionInfo(compositionBlock, ins);
+
+ return ins.execute();
+ }
+
+ /**
+ * Handles composition of blocks. Only array composition is supported so far.
+ *
+ * @param compositionBlock
+ * The composition Block, may be null.
+ * @param ins the insert statement for a MeaQuantity
+ * @throws IOException
+ */
+ private void handleCompositionInfo(BLOCK compositionBlock, ODSInsertStatement ins) throws IOException
+ {
+ if (compositionBlock == null)
+ {
+ return;
+ }
+
+ CABLOCK arrayCompositionBlock = null;
+ if (compositionBlock instanceof CNBLOCK) {
+ throw new IOException("Channel Composition based on compact structures not yet supported!");
+ } else if (compositionBlock instanceof CABLOCK) {
+ LOG.debug("Array block for composition: [" + compositionBlock + "]");
+ arrayCompositionBlock = (CABLOCK)compositionBlock;
+ }
+
+ if (arrayCompositionBlock != null)
+ {
+ handleArrayComposition(arrayCompositionBlock, ins);
+ }
+ }
+
+ /**
+ * Handles array compositions. The ods information on rank and dimension is
+ * read from the CABLOCK. Additionally the inverse layout flag has to be
+ * transferred as well, otherwise no client may correctly calculate the values
+ * from the tensor in this channel. This additional flag is not yet specified
+ * by ODS, but will be written as an application attribute 'columnOriented' to
+ * the MeaQuantity.
+ *
+ * @param arrayCompositionBlock
+ * @param ins the insert statement for a MeaQuantity
+ * @throws IOException
+ */
+ private void handleArrayComposition(CABLOCK arrayCompositionBlock, ODSInsertStatement ins) throws IOException
+ {
+ if (arrayCompositionBlock == null || ins == null)
+ {
+ return;
+ }
+
+ // set the rank attribute of the MeaQuantity
+ int odsRank = arrayCompositionBlock.getNrOfDimensions();
+ ins.setLongVal(ODSModelCache.ATTR_NAME_MEAQU_RANK, odsRank);
+
+ // set the dimension attribute of the MeaQuantity
+ long[] longDimSizes = arrayCompositionBlock.getDimSizes();
+ int[] odsDimension = new int[longDimSizes.length];
+ for (int i = 0; i < longDimSizes.length; i++)
+ {
+ long currentDimSize = longDimSizes[i];
+ if (currentDimSize > Integer.MAX_VALUE)
+ {
+ throw new IOException("Found dimension (index=" + i + ") in MDF with more values (" + currentDimSize
+ + ") than can be handled by ODS!");
+ }
+ odsDimension[i] = (int) currentDimSize;
+ }
+ ins.setLongSeq(ODSModelCache.ATTR_NAME_MEAQU_DIMENSION, odsDimension);
+
+ // set the ColumnOriented attribute of the MeaQuantity
+ boolean odsInverseLayout = arrayCompositionBlock.isFlagSet(CABLOCK.FLAG_INVERSE_LAYOUT);
+ ins.setBooleanVal(ODSModelCache.ATTR_NAME_MEAQU_COL_ORIENTED_TENSOR, odsInverseLayout);
+
+ // TODO handle working points
+
+ // handle scaling axes
+ if (arrayCompositionBlock.isFlagSet(CABLOCK.FLAG_SCALING_AXIS_DEFINED))
+ {
+ if (arrayCompositionBlock.isFlagSet(CABLOCK.FLAG_FIXED_AXES))
+ {
+// throw new IOException("Handling of fixed scaling axes for arrays is not yet implemented!");
+ }
+ else
+ {
+// throw new IOException("Handling of variable scaling axes for arrays is not yet implemented!");
+ }
+ }
}
/**
@@ -843,8 +945,12 @@
* The Channel Block.
* @param ccBlock
* The Conversion Block.
+ * @param compositionBlock
+ * The composition Block.
* @param lcName
* The Name the Local Column will have.
+ * @param iidMea
+ * The ID of the Measurement this LocalColumn's SubMatrix will be related to in case of array composition.
* @param iidMeq
* The ID of the SubMatrix this LocalColumn is related to.
* @param iidMeq
@@ -858,13 +964,13 @@
* If an I/O-error occurs.
* @throws AoException
*/
- long createLocalColumn(ODSModelCache modelCache, DGBLOCK dgBlock, CGBLOCK cgBlock, CNBLOCK cnBlock, CCBLOCK ccBlock,
- String lcName, long iidSm, long iidMeq, long[] iidPrevSm, String mimeType) throws IOException, AoException {
+ long createLocalColumn(ODSModelCache modelCache, DGBLOCK dgBlock, CGBLOCK cgBlock, CNBLOCK cnBlock, CCBLOCK ccBlock,
+ BLOCK compositionBlock, String lcName, long iidMea, long iidSm, long iidMeq, long[] iidPrevSm, String mimeType)
+ throws IOException, AoException {
int seqRep = getSeqRep(cnBlock, ccBlock);
double[] genParams = getGenerationParameters(ccBlock);
ODSInsertStatement ins = new ODSInsertStatement(modelCache, "lc");
ins.setStringVal("iname", lcName);
- ins.setLongLongVal("sm", iidSm);
// MIME-Type
if (mimeType != null) {
@@ -875,9 +981,7 @@
// sequence_representation: string channels cannot be referenced in ASAM
// ODS: read and write external
- if (cnBlock.getDataType() >= 6 && cnBlock.getDataType() <= 9 && cnBlock.getChannelType() != 1) { // 6
- // To
- // 9:
+ if (cnBlock.getDataType() >= 6 && cnBlock.getDataType() <= 9 && cnBlock.getChannelType() != 1) { // 6 To 9:
// Datatype
// String
String[] stringDataValues = readStringDataValues(dgBlock, cgBlock, cnBlock);
@@ -894,7 +998,7 @@
}
// independent flag
- short idp = cnBlock.getChannelType() > 0 ? (short) 1 : (short) 0;
+ short idp = cnBlock.getSyncType() > 0 ? (short) 1 : (short) 0;
ins.setShortVal("idp", idp);
// generation parameters
@@ -906,7 +1010,7 @@
ins.setEnumVal("rdt", rawDataType);
// axistype
- int axistype = cnBlock.getChannelType() == 0 ? 1 : 0;
+ int axistype = cnBlock.getSyncType() == 0 ? 1 : 0;
ins.setEnumVal("axistype", axistype);
// minimum/maximum
if (cnBlock.isValueRangeValid()) {
@@ -914,13 +1018,74 @@
ins.setDoubleVal("max", cnBlock.getValRangeMax());
}
+ // identify the actual SubMatrix to connect to
+ long actualSubMatrixId = identifySubMatrixIdToConnect(modelCache, cgBlock, compositionBlock, iidSm, iidMea);
+
// relation to submatrix
- ins.setLongLongVal("sm", iidSm);
+ ins.setLongLongVal("sm", actualSubMatrixId);
ins.setLongLongVal("meq", iidMeq);
long iidLc = ins.execute();
return iidLc;
}
+
+ /**
+ * For array composition, the nrOfValues for the SubMatrix has to be
+ * corrected. An according array channel will have the following length:
+ * cycleCount * dimSize1 * ... * dimSizeN
+ * Therefore a new SubMatrix with this nrOfRows may have to be created.
+ * If one with this length was already created, its ID is returned. If no
+ * composition was passed, the original SubMatrix ID is returned.
+ *
+ * @param modelCache
+ * Cache with model Objects.
+ * @param cgBlock
+ * The CGBLOCK.
+ * @param compositionBlock
+ * The composition Block.
+ * @param originalSmId
+ * If compositionBlock is null, this ID will be returned.
+ * @param iidMea
+ * The measurement ID to connect a newly created SubMatrix to.
+ * @return SubMatrix ID to be used for the LocalColumn, for which this method was called.
+ * @throws AoException
+ */
+ private long identifySubMatrixIdToConnect(ODSModelCache modelCache, CGBLOCK cgBlock, BLOCK compositionBlock, long originalSmId,
+ long iidMea) throws AoException
+ {
+ long actualSubMatrixId = originalSmId;
+ if (compositionBlock instanceof CABLOCK && iidMea > 0) {
+ long smNrOfValues = cgBlock.getCycleCount();
+ long[] dimSizes = ((CABLOCK)compositionBlock).getDimSizes();
+ for (long dimSize : dimSizes)
+ {
+ smNrOfValues *= dimSize;
+ }
+
+ Long existingArraySubmatrixId = arraySubMatrixIDsByNrOfValues.get(smNrOfValues);
+
+ if (existingArraySubmatrixId == null)
+ {
+ // create array SubMatrix instance
+ ODSInsertStatement smIns = new ODSInsertStatement(modelCache, "sm");
+ String smName = "sm_arrays_" + smNrOfValues;
+ smIns.setStringVal("iname", smName);
+
+ LOG.debug("SubMatrix name: " + smName);
+
+ smIns.setLongVal("rows", (int) smNrOfValues);
+ // Relation to measurement
+ smIns.setLongLongVal("mea", iidMea);
+ actualSubMatrixId = smIns.execute();
+ arraySubMatrixIDsByNrOfValues.put(smNrOfValues, actualSubMatrixId);
+ }
+ else
+ {
+ actualSubMatrixId = existingArraySubmatrixId;
+ }
+ }
+ return actualSubMatrixId;
+ }
/**
* Read values from an VLSD-Channel and write them directly to file.
@@ -1150,6 +1315,8 @@
* The CNBLOCK.
* @param ccBlock
* The CCBLOCK.
+ * @param compositionBlock
+ * The composition Block, may be null.
* @param sectionstart
* The link to data, can be a DL, RD or DT Block or HL, DZ, but
* these are not supported.
@@ -1165,18 +1332,16 @@
* Error reading from MDF file.
*/
void writeEc(ODSModelCache modelCache, long iidLc, IDBLOCK idBlock, DGBLOCK dgBlock, CGBLOCK cgBlock,
- CNBLOCK cnBlock, CCBLOCK ccBlock, long sectionstart, int parity) throws AoException, IOException {
+ CNBLOCK cnBlock, CCBLOCK ccBlock, BLOCK compositionBlock, long sectionstart, int parity) throws AoException, IOException {
if (isRatConv2ExtComp(ccBlock)) {
// NOTE: once CCBLOCK is no longer required, it should be removed
// from this method's signature!
createCustomRatConvEC(modelCache, iidLc, idBlock, dgBlock, cgBlock, cnBlock, ccBlock, sectionstart, parity);
} else {
- ODSInsertStatement ins = new ODSInsertStatement(modelCache, "ec");
-
DLBLOCK currdl = null; // current list block
int dlindex = 0; // index in data list block.
- int totalindex = 0; // nuber of blocks read;
+ int totalindex = 0; // number of blocks read;
long currblock = -1;
switch (BLOCK.getBlockType(idBlock.sbc, sectionstart)) {
@@ -1197,6 +1362,7 @@
throw new IOException("Zipped blocks cannot be parsed into the ODS-Format.");
}
+ ODSInsertStatement ins = new ODSInsertStatement(modelCache, "ec");
while (currblock != -1) {
ins.setStringVal("iname", "ec_" + countFormat.format(++totalindex));
Path mdfFilePath = idBlock.getMdfFilePath().getFileName();
@@ -1212,8 +1378,20 @@
ins.setEnumVal("vt", vt);
ins.setLongLongVal("so", startOffset);
+ int valuesPerBlock = 1; // default is one value per block
+ if (compositionBlock != null)
+ {
+ if (compositionBlock instanceof CABLOCK) {
+ // for array composition set valuesPerBlock to the product of all dim sizes
+ long[] dimSizes = ((CABLOCK)compositionBlock).getDimSizes();
+ for (long dimSize : dimSizes)
+ {
+ valuesPerBlock *= dimSize;
+ }
+ }
+ }
// TODO Strings, write number of Bytes? Spec4/61
- ins.setLongVal("vb", 1); // one value per block
+ ins.setLongVal("vb", valuesPerBlock);
// Calculate ByteSize and Offset
long bytesize;
@@ -1236,13 +1414,25 @@
int cycleCount = -1;
if (BLOCK.getBlockType(idBlock.sbc, currblock).equals(DTBLOCK.BLOCK_ID)) {
cycleCount = (int) ((DTBLOCK.read(idBlock.sbc, currblock).getLength() - 24) / bytesize);
- ins.setLongVal("cl", cycleCount);
} else if (BLOCK.getBlockType(idBlock.sbc, currblock).equals(RDBLOCK.BLOCK_ID)) {
cycleCount = (int) ((RDBLOCK.read(idBlock.sbc, currblock).getLength() - 24) / bytesize);
- ins.setLongVal("cl", cycleCount);
} else {
}
+
+ // for array composition the component length must be adjusted like for the SubMatrix nrOfRows
+ if (compositionBlock != null)
+ {
+ if (compositionBlock instanceof CABLOCK) {
+ long[] dimSizes = ((CABLOCK)compositionBlock).getDimSizes();
+ for (long dimSize : dimSizes)
+ {
+ cycleCount *= dimSize;
+ }
+ }
+ }
+
+ ins.setLongVal("cl", cycleCount);
// export flags
exportFlags(ins, idBlock, dgBlock, cgBlock, cnBlock, startOffset, cycleCount);
@@ -1598,7 +1788,7 @@
// 4 IEEE 754 floating-point format LEO
else if (dt == 4) {
- if (nb == 32 && bitOffset == 0) { // 32 bit: ieeefloat4
+ if (nb == 32 && bitOffset == 0) { // 32 bit: ieeefloat4
return 5;
} else if (nb == 64 && bitOffset == 0) { // 64 bit: ieeefloat8
return 6;
@@ -1738,7 +1928,7 @@
else if (typeSpec == 31 || typeSpec == 32) {
int dt = cnBlock.getDataType();
int nb = (int) cnBlock.getBitCount();
- if ((dt == 2 || dt == 3 || dt == 11 || dt == 12 || dt == 15 || dt == 16) && nb == 32) { // ieeefloat4,
+ if ((dt == 2 || dt == 3 || dt == 11 || dt == 12 || dt == 15 || dt == 16) && (nb == 16 || nb == 32)) { // half precision floating point, ieeefloat4,
// ieeefloat4_beo
ret = 3; // DT_FLOAT
} else if ((dt == 2 || dt == 3 || dt == 11 || dt == 12 || dt == 15 || dt == 16) && nb == 64) { // ieeefloat8,
@@ -1841,7 +2031,9 @@
} else if ((dt == 2 || dt == 3) && nb >= 33 && nb <= 64) { // dt_longlong,
// dt_longlong_beo
return expandDataType ? 7 : 8; // [DT_DOUBLE] DT_LONGLONG
- } else if ((dt == 4 || dt == 5) && nb == 32) { // ieeefloat4,
+ } else if ((dt == 4 || dt == 5) && nb == 16) { // half precision floating point
+ return 3; // DT_FLOAT
+ } else if ((dt == 4 || dt == 5) && nb == 32) { // ieeefloat4,
// ieeefloat4_beo
return 3; // DT_FLOAT
} else if ((dt == 4 || dt == 5) && nb == 64) { // ieeefloat8,
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/BlockReferenceTriple.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/BlockReferenceTriple.java
new file mode 100644
index 0000000..87ec805
--- /dev/null
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/BlockReferenceTriple.java
@@ -0,0 +1,54 @@
+package org.eclipse.mdm.openatfx.mdf.mdf4;
+
+/**
+ * <p> Title: {@link BlockReferenceTriple} </p>
+ *
+ * <b>Description:</b>
+ * <p> Storage class for a reference triple used at some points in an mdf file. </p>
+ *
+ * @author Markus Renner
+ *
+ * <p>Company: Peak Solution GmbH</p>
+ *
+ * $Rev: $: Revision of last commit<br/>
+ * $Author: $: Author of last commit<br/>
+ * $Date: $: Date of last commit
+ *
+ */
+public class BlockReferenceTriple
+{
+ private final long dgBlockOffset;
+ private final long cgBlockOffset;
+ private final long cnBlockOffset;
+
+ public BlockReferenceTriple(long dgBlockOffset, long cgBlockOffset, long cnBlockOffset)
+ {
+ this.dgBlockOffset = dgBlockOffset;
+ this.cgBlockOffset = cgBlockOffset;
+ this.cnBlockOffset = cnBlockOffset;
+ }
+
+ /**
+ * @return the dgBlockOffset
+ */
+ public long getDgBlockOffset()
+ {
+ return dgBlockOffset;
+ }
+
+ /**
+ * @return the cgBlockOffset
+ */
+ public long getCgBlockOffset()
+ {
+ return cgBlockOffset;
+ }
+
+ /**
+ * @return the cnBlockOffset
+ */
+ public long getCnBlockOffset()
+ {
+ return cnBlockOffset;
+ }
+}
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CABLOCK.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CABLOCK.java
new file mode 100644
index 0000000..a65bdbf
--- /dev/null
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CABLOCK.java
@@ -0,0 +1,892 @@
+package org.eclipse.mdm.openatfx.mdf.mdf4;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.SeekableByteChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CABLOCK extends BLOCK
+{
+ public static final String BLOCK_ID = "##CA";
+
+ /**
+ * Array of composed elements: Pointer to a CNBLOCK for array of structures, or to a CABLOCK for array of arrays (can be NIL).
+ * If a CABLOCK is referenced, it must use the "CN template" storage type (ca_storage = 0).
+ */
+ private long lnkComposition;
+
+ /**
+ * List of links to either a data block (DTBLOCK or DZBLOCK for this block type) or a data list block (DLBLOCK of data blocks or its HLBLOCK) for each element.
+ * <p>
+ * Only present for storage type "DG template" (ca_storage = 2)!
+ * </p>
+ * <p>
+ * A link in this list may only be NIL if the cycle count of the respective element is 0: ca_data[k] = NIL => ca_cycle_count[k] = 0<br>
+ * The links are stored line-oriented, i.e. element k uses ca_data[k]. The size of the list must be equal to Π N(d),
+ * i.e. to the product of the number of elements per dimension N(d) over all dimensions D.<br>
+ * </p>
+ * <p>
+ * Note: link ca_data[0] must be equal to dg_data link of the parent DGBLOCK.
+ * </p>
+ */
+ private long[] lnksData;
+
+ /**
+ * References to channels for size signal of each dimension (can be NIL).
+ * <p>
+ * Only present if "dynamic size" flag (bit 0) is set.
+ * </p>
+ * <p>
+ * Each reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel
+ * (either all three links are assigned or NIL). Thus the links have the following order:<br>
+ * DGBLOCK for size signal of dimension 1<br>
+ * CGBLOCK for size signal of dimension 1<br>
+ * CNBLOCK for size signal of dimension 1<br>
+ * …<br>
+ * DGBLOCK for size signal of dimension D<br>
+ * CGBLOCK for size signal of dimension D<br>
+ * CNBLOCK for size signal of dimension D<br>
+ * </p>
+ * <p>
+ * The size signal can be used to model arrays whose number of elements per dimension can vary over time.
+ * If a size signal is specified for a dimension, the number of elements for this dimension at some point in time
+ * is equal to the value of the size signal at this time (i.e. for time-synchronized signals,
+ * the size signal value with highest time stamp less or equal to current time stamp).
+ * If the size signal has no recorded signal value for this time (yet), assume 0 as size.
+ * </p>
+ * <p>
+ * Since each referenced channel defines the current size of a dimension, its physical values must be Integer values ≥ 0 and ≤ N(d),
+ * i.e. the values must not exceed the maximum number of elements for the respective dimension.
+ * Usually, a size signal should have some Integer data type (cn_data_type ≤ 3) without conversion rule and without unit.
+ * </p>
+ * <p>
+ * Since the size signal and the array signal must be synchronized, their channel groups must contain at least one common master channel type.
+ * </p>
+ * <p>
+ * Note: the "positions" of the array elements are fixed as defined for the maximum allowed array size.
+ * They will not change when the array is reduced by a size signal value less than N(d).
+ * However, the "removed" array elements must not be considered.
+ * For row-oriented CN template storage, the elements would be stored in the record in following order:<br>
+ * a11, a12, a13, a21, a22, a23<br>
+ * Assume that the size of the second dimension is reduced from 3 to 2. Then the values of elements a13 and a23
+ * will be undefined and should not be used. However, the other elements stay at the same position (Byte offset).<br>
+ * a11, a12, [a13], a21, a22, [a23]
+ * </p>
+ */
+ private long[] lnksDynamicSize;
+
+ /**
+ * Reference to channels for input quantity signal for each dimension (can be NIL).
+ * <p>
+ * Only present if "input quantity" flag (bit 1) is set.
+ * </p>
+ * <p>
+ * Reference to channels for input quantity signal for each dimension (can be NIL).
+ * Each reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and
+ * CNBLOCK for the channel (either all three links are assigned or NIL). Thus the links have the following order:<br>
+ * DGBLOCK for input quantity of dimension 1<br>
+ * CGBLOCK for input quantity of dimension 1<br>
+ * CNBLOCK for input quantity of dimension 1<br>
+ * …<br>
+ * DGBLOCK for input quantity of dimension D<br>
+ * CGBLOCK for input quantity of dimension D<br>
+ * CNBLOCK for input quantity of dimension D<br>
+ * </p>
+ * <p>
+ * Since the input quantity signal and the array signal must be synchronized,
+ * their channel groups must contain at least one common master channel type.
+ * </p>
+ * <p>
+ * The input quantity often is denoted as "working point" because it is used for look-up of a value in the array.<br>
+ * For array type "look-up", the value of the input quantity will be used for looking up a value in the
+ * scaling axis of the respective dimension (either axis channel or fixed axis values listed in ca_axis_value list).<br>
+ * For array type "scaling axis", the value of the input quantity will be used for looking up a value in the axis itself.
+ * The input quantity should have the same physical unit as the axis it is applied to.
+ * </p>
+ */
+ private long[] lnksInputQuantity;
+
+ /**
+ * Reference to channel for output quantity (can be NIL).
+ * <p>
+ * Only present if "output quantity" flag (bit 2) is set.
+ * </p>
+ * <p>
+ * The reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel
+ * (either all three links are assigned or NIL). Since the output quantity signal and the array signal must be synchronized,
+ * their channel groups must contain at least one common master channel type.
+ * For array type "look-up", the output quantity is the result of the complete look-up.
+ * The output quantity should have the same physical unit as the array elements of the array that references it.
+ * </p>
+ */
+ private long[] lnksOutputQuantity;
+
+ /**
+ * Reference to channel for comparison quantity (can be NIL).
+ * <p>
+ * Only present if "comparison quantity" flag (bit 3) is set.
+ * </p>
+ * <p>
+ * The reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel
+ * (either all three links are assigned or NIL). Since the comparison quantity signal and the array signal must be synchronized,
+ * their channel groups must contain at least one common master channel type.
+ * The comparison quantity should have the same physical unit as the array elements.
+ * </p>
+ */
+ private long[] lnksComparisonQuantity;
+
+ /**
+ * Pointer to a conversion rule (CCBLOCK) for the axis of each dimension. If a link NIL a 1:1 conversion must be used for this axis.
+ * <p>
+ * Only present if "axis" flag (bit 4) is set.
+ * </p>
+ * <p>
+ * If the "fixed axis" flag (Bit 5) is set, the conversion must be applied to the fixed axis values of the respective axis/dimension
+ * (ca_axis_value list stores the raw values as REAL). If the link to the CCBLOCK is NIL already the physical values are stored
+ * in the ca_axis_value list. If the "fixed axes" flag (Bit 5) is not set, the conversion must be applied to the raw values
+ * of the respective axis channel, i.e. it overrules the conversion specified for the axis channel, even if the ca_axis_conversion link is NIL!<br>
+ * </p>
+ * <p>
+ * Note: ca_axis_conversion may reference the same CCBLOCK as referenced by the respective axis channel ("sharing" of CCBLOCK).
+ * </p>
+ */
+ private long[] lnksConversionRule;
+
+ /**
+ * References to channels for axis of respective dimension (can be NIL).
+ * <p>
+ * Only present if "axis" flag (bit 4) is set and "fixed axes flag" (bit 5) is not set.
+ * </p>
+ * <p>
+ * Each reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel
+ * (either all three links are assigned or NIL). Thus the links have the following order:<br>
+ * DGBLOCK for axis of dimension 1<br>
+ * CGBLOCK for axis of dimension 1<br>
+ * CNBLOCK for axis of dimension 1<br>
+ * …<br>
+ * DGBLOCK for axis of dimension D<br>
+ * CGBLOCK for axis of dimension D<br>
+ * CNBLOCK for axis of dimension D<br>
+ * </p>
+ * <p>
+ * Each referenced channel must be an array of type "scaling axis" or "interval axis".<br>
+ * For a "scaling axis" the maximum number of elements (ca_dim_size[0] in axis) must not be less than the maximum number of elements
+ * of the respective dimension d in the array which references it (ca_dim_size[d-1]).<br>
+ * For an "interval axis" the number of elements must be exactly one more than respective dimension d
+ * in the "classification result" array (ca_dim_size[d-1]+1).
+ * </p>
+ * <p>
+ * If an axis signal must be synchronized with the array signal (e.g. for dynamic size axis),
+ * the channel groups of the axis and the array signal must contain at least one common master channel type.
+ * If a fixed axis is stored by an axis channel, its channel group should only contain one cycle.
+ * </p>
+ * <p>
+ * If a reference to an axis is NIL, there is no axis and a zero-based index should be used for axis values.
+ * </p>
+ */
+ private long[] lnksScalingAxis;
+
+ /**
+ * <b>Array type</b> (defines semantic of the array)
+ * <p>Attention: for some array types certain features are not allowed (see ca_flags)</p>
+ * <p><ul>
+ * <li>0 = Array<br>
+ * The array is a simple D-dimensional value array (value block) without axes and without input/output/comparison quantities.
+ *
+ * <li>1 = Scaling axis<br>
+ * The array is a scaling axis (1-dimensional vector), possibly referenced by one or more arrays.
+ * If referenced by an array of type "look-up", the axis itself may have a scaling axis (e.g. CURVE_AXIS) and an own input quantity.
+ *
+ * <li>2 = Look-up<br>
+ * The array is a D-dimensional array with axes. It can have input/output/comparison quantities.
+ *
+ * <li>3 = Interval axis<br>
+ * The array is an axis (1-dimensional vector) defining interval ranges as "axis points".
+ * It can be referenced by one or more arrays of type "classification result" (ca_type = 4).
+ * The interval axis must have at least two elements (ca_dim_size[0] = N(0) > 1)
+ * and the physical values of the elements must be strictly monotonous increasing over the element index,
+ * i.e. ai < ai+1 for 1 ≤ i < N(0)<br>
+ * In contrast to a scaling axis (ca_type = 1), an interval axis always has one element more than the number of elements
+ * for the respective dimension of the classification result array which references it.
+ * The elements of the class interval axis define the borders of interval ranges that are seen as axis points.
+ * Depending on the "left-open interval" flag (bit 7 in ca_flags), the intervals are defined as<br>
+ * ]ao,a1], ]a1,a2], …, ]aN(0)-1,aN(0)] (flag set)<br>
+ * [ao,a1[, [a1,a2[, …, [aN(0)-1,aN(0)[ (flag not set)<br>
+ * valid since MDF 4.1.0, should not occur for earlier versions
+ *
+ * <li>4 = Classification result<br>
+ * The array is a D-dimensional array containing classification results.
+ * It can have scaling axes (ca_type = 1) or interval axes (ca_type = 3), even mixed.
+ * Details about the classification method and parameters can be given as XML tags in cn_md_comment
+ * of the parent CN block and the CN blocks of the axes.<br>
+ * valid since MDF 4.1.0, should not occur for earlier versions
+ * </ul><p>
+ */
+ private byte arrayType;
+ public static final byte ARRAYTYPE_ARRAY = 1;
+ public static final byte ARRAYTYPE_SCALING_AXIS = 1 << 1;
+ public static final byte ARRAYTYPE_LOOKUP = 1 << 2;
+ public static final byte ARRAYTYPE_INTERVAL_AXIS = 1 << 3;
+ public static final byte ARRAYTYPE_CLASSIFICATION_RESULT = 1 << 4;
+
+ /**
+ * <b>Storage type</b (defines how the element values are stored)
+ * <p><ul>
+ * <li>0 = CN template<br>
+ * Values of all elements of the array are stored in the same record (i.e. all elements are measured together).
+ * The parent CNBLOCK defines the first element in the record (k = 0).
+ * All other elements are defined by the same CNBLOCK except that the values for cn_byte_offset
+ * and cn_inval_bit_pos change for each component.
+ *
+ * <li>1 = CG template<br>
+ * Value for each element of the array is stored in a separate record (i.e. elements are stored independently of each other).
+ * All records are stored in the same data block referenced by the parent DGBLOCK.
+ * As a consequence the data group (and thus the MDF file) is unsorted.
+ * All elements have exactly the same record layout specified by the parent CGBLOCK.
+ * However, each element uses a different cycle count (given by ca_cycle_count[k])
+ * and a different record ID which must be calculated by "auto-increment" of the record ID of the parent CGBLOCK:
+ * cg_record_id + k.<br> Since ca_cycle_count[0] must be equal to cg_cycle_count of the parent CGBLOCK,
+ * the parent CNBLOCK of the CABLOCK automatically describes the first array element (k = 0).
+ * When sorting a data group, a CABLOCK with "CG template" storage will be converted to a CABLOCK with "DG template" storage.
+ *
+ * <li>2 = DG template<br>
+ * Similar to CG template, the value of each element of the array is stored in a separate record (i.e. elements are stored independently of each other).
+ * However, the records for each element are stored in separate data blocks referenced by the list of links in ca_data.
+ * Similar to "CG template" storage, all elements have exactly the same record layout (defined by the parent CGBLOCK)
+ * but a different cycle count (specified by ca_cycle_count[k]).<br>
+ * Since ca_cycle_count[0] must be equal to cg_cycle_count of the parent CGBLOCK, and ca_data[0] must be equal to
+ * dg_data of the parent DGBLOCK, the parent CNBLOCK of the CABLOCK automatically describes the first array element (k = 0).
+ * </ul></p>
+ */
+ private byte storageType;
+ public static final byte STORAGETYPE_CN_TEMPLATE = 1;
+ public static final byte STORAGETYPE_CG_TEMPLATE = 1 << 1;
+ public static final byte STORAGETYPE_DG_TEMPLATE = 1 << 2;
+
+ /**
+ * <b>Flags (0-based!)</b>
+ * <p> The value contains the following bit flags (Bit 0 = LSB):
+ * <ul>
+ * <li>Bit 0: dynamic size flag<br>
+ * If set, the number of scaling points for the array is not fixed but can vary over time.
+ * Can only be set for array types "look-up" and "scaling axis".
+ *
+ * <li>Bit 1: input quantity flag<br>
+ * If set, a channel for the input quantity is specified for each dimension by ca_input_quantity.
+ * Can only be set for array types "look-up" and "scaling axis".
+ *
+ * <li>Bit 2: output quantity flag<br>
+ * If set, a channel for the output quantity is specified by ca_output_quantity. Can only be set for array type "look-up".
+ *
+ * <li>Bit 3: comparison quantity flag<br>
+ * If set, a channel for the comparison quantity is specified by ca_comparison_quantity. Can only be set for array type "look-up".
+ *
+ * <li>Bit 4: axis flag<br>
+ * If set, a scaling axis is given for each dimension of the array, either as fixed or as dynamic axis,
+ * depending on "fixed axis" flag (bit 5). Can only be set for array types "look-up", "scaling axis" and "classification result".
+ *
+ * <li>Bit 5: fixed axis flag<br>
+ * If set, the scaling axis is fixed and the axis points are stored as raw values in ca_axis_value list.
+ * If not set, the scaling axis may vary over time and the axis points are stored as channel referenced in ca_axis for each dimension.
+ * Only relevant if "axis" flag (bit 4) is set. Can only not be set for array types "look-up" and "scaling axis".
+ *
+ * <li>Bit 6: inverse layout flag<br>
+ * If set, the record layout is "column oriented" instead of "row oriented".
+ * Only relevant for "CN template" storage type and for number of dimensions > 1.
+ *
+ * <li>Bit 7: left-open interval flag<br>
+ * If set, the interval ranges for the class interval axes are left-open and right-closed, i.e. ]a,b] = {x | a < x ≤ b}.<br>
+ * If not set, the interval ranges for the class interval axes are left-closed and right-open, i.e. [a,b[ = {x | a ≤ x < b}.<br>
+ * Note that opening or closing is irrelevant for infinite endpoints (there can only be -INF for the left border of the
+ * very first interval, or +INF for right border of the very last interval).
+ * Only relevant for array type "interval axes".<br>
+ * valid since MDF 4.1.0, should not be set for earlier versions
+ * </ul></p>
+ */
+ private long flags;
+ public static final byte FLAG_DYNAMIC_SIZE = 1;
+ public static final byte FLAG_INPUT_QUANTITY_DEFINED = 1 << 1;
+ public static final byte FLAG_OUTPUT_QUANTITY_DEFINED = 1 << 2;
+ public static final byte FLAG_COMPARISON_QUANTITY_DEFINED = 1 << 3;
+ public static final byte FLAG_SCALING_AXIS_DEFINED = 1 << 4;
+ public static final byte FLAG_FIXED_AXES = 1 << 5;
+ public static final byte FLAG_INVERSE_LAYOUT = 1 << 6;
+ public static final byte FLAG_LEFT_OPEN_INTERVALS = -128;
+
+ /**
+ * Base factor for calculation of Byte offsets for "CN template" storage type.
+ * <p>The absolute value of ca_byte_offset_base should be larger than or equal to the size of Bytes required
+ * to store a component channel value in the record (all must have the same size).
+ * If the values are equal, then the component values are stored contiguously, i.e.next to each other without gaps.
+ * If ca_byte_offset_base is negative, the component values are stored with decreasing index.</p>
+ */
+ private long byteOffsetBase;
+
+ /**
+ * Base factor for calculation of invalidation bit positions for CN template storage type.
+ * <p>For a simple array which is not part of a nested composition,
+ * ca_inval_bit_pos_base = 1 means that the invalidation bits for the component channels are stored without gaps and
+ * ca_inval_bit_pos_base = 0 means that all component channels use the same invalidation bit in the record.
+ */
+ private long invalBitPosBase;
+
+ /**
+ * Maximum number of elements for each dimension N(d).
+ * <p>N(d) > 0 for all d. <br>For array type "interval axis", there must be at least two elements, i.e. N(0) > 1.</p>
+ */
+ private long[] dimSizes;
+
+ /**
+ * Number of dimensions D > 0<br>
+ * For array type "scaling axis" or "interval axis", D must be 1.
+ */
+ private int nrOfDimensions;
+
+ /**
+ * List of raw values for (fixed) axis points of each axis.
+ * <p>Only present if "fixed axes" flag (bit 5) is set!</p>
+ * <p>
+ * List of raw values for (fixed) axis points of each axis. The axis points are stored in a linear sequence for each dimension:<br>
+ * A1(1), A1(2), ..., A1(N(1)),<br>
+ * A2(1), A2(2), ..., A2(N(2)),<br>
+ * ...<br>
+ * AD(1), AD(2), ..., AD(N(D))<br>
+ * where Ad(j) is axis point j of dimension d and N(d) is the number of elements for dimension d.<br>
+ * Example for D = 2 dimensions (as explained later Y axis for A1 and X axis for A2):<br>
+ * Y(1), Y(2), ..., Y(N(1)),<br>
+ * X(1), X(2), ..., X(N(2))<br>
+ * The size of the list must be equal to Σ N(d) = the sum of the number of elements per dimension N(d) over all dimensions D.
+ * To convert the raw axis values to physical values, the conversion rule of the respective dimension must be applied
+ * (CCBLOCK referenced by ca_cc_axis_conversion[i]). If the CCBLOCK link of a dimension is NIL,
+ * the raw values are equal to the physical values (1:1 conversion).
+ * </p>
+ */
+ private double[] axisValues;
+
+ /**
+ * List of cycle counts for each element in case of "CG/DG template" storage.
+ * <p>Only present for storage types "CG/DG template"!</p>
+ * <p>
+ * List of cycle counts for each element in case of "CG/DG template" storage. The offsets are stored line-oriented,
+ * i.e. element k uses ca_cycle_count[k]<br>
+ * The size of the list must be equal to Π N(d) = the product of the number of elements per dimension N(d) over all dimensions D.<br>
+ * Note: ca_cycle_count[0] must be equal to cg_cycle_count of parent CGBLOCK!
+ * </p>
+ */
+ private long[] cycleCounts;
+
+ private CABLOCK(SeekableByteChannel sbc, long pos)
+ {
+ super(sbc, pos);
+ }
+
+ /**
+ * Reads a CABLOCK from the channel starting at current channel position.
+ *
+ * @param channel
+ * The channel to read from.
+ * @param pos
+ * The position
+ * @return The block data.
+ * @throws IOException
+ * The exception.
+ */
+ public static CABLOCK read(SeekableByteChannel channel, long pos) throws IOException {
+ CABLOCK block = new CABLOCK(channel, pos);
+
+ // read block header
+ ByteBuffer bb = ByteBuffer.allocate(24);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ channel.position(pos);
+ channel.read(bb);
+ bb.rewind();
+
+ // CHAR 4: Block type identifier
+ block.setId(MDF4Util.readCharsISO8859(bb, 4));
+ if (!block.getId().equals(BLOCK_ID)) {
+ throw new IOException("Wrong block type - expected '" + BLOCK_ID + "', found '" + block.getId() + "'");
+ }
+
+ // BYTE 4: Reserved used for 8-Byte alignment
+ bb.get(new byte[4]);
+
+ // UINT64: Length of block
+ block.setLength(MDF4Util.readUInt64(bb));
+
+ // UINT64: Number of links
+ block.setLinkCount(MDF4Util.readUInt64(bb));
+
+ // read block data
+ bb = ByteBuffer.allocate((int) block.getLength() - 24);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ channel.position(pos + 24);
+ channel.read(bb);
+ bb.rewind();
+
+ // read links
+ long[] lnks = new long[(int) block.getLinkCount()];
+ for (int i = 0; i < lnks.length; i++) {
+ lnks[i] = MDF4Util.readLink(bb);
+ }
+
+ // read data
+
+ // UINT8: Array type (ca_type)
+ byte arrayType = MDF4Util.readUInt8(bb);
+ block.setArrayType(arrayType);
+
+ // UINT8: Storage type (ca_storage)
+ byte storageTyp = MDF4Util.readUInt8(bb);
+ block.setStorageType(storageTyp);
+
+ // UINT16: Number of dimensions (ca_ndim)
+ int nrOfDims = MDF4Util.readUInt16(bb);
+ block.setNrOfDimensions(nrOfDims);
+
+ // UINT32: Flags (ca_flags)
+ long readFlags = MDF4Util.readUInt32(bb);
+ block.setFlags(readFlags);
+
+ // INT32: Byte offset base (ca_byte_offset_base)
+ block.setByteOffsetBase(MDF4Util.readInt32(bb));
+
+ // UINT32: Invalidation bit position base (ca_inval_bit_pos_base)
+ block.setInvalidationBitPositionBase(MDF4Util.readUInt32(bb));
+
+ // UINT64: Maximum size of each dimension (ca_dim_size)
+ List<Long> dimSizesList = new ArrayList<>();
+ for (int i = 0; i < nrOfDims; i++) {
+ dimSizesList.add(MDF4Util.readUInt64(bb));
+ }
+ block.setDimSizes(dimSizesList);
+
+ long sumNumberOfValuesPerDimension = dimSizesList.stream().mapToLong(Long::longValue).sum();
+ long productNumberOfValuesPerDimension = dimSizesList.stream().mapToLong(Long::longValue).reduce(1, (a, b) -> a * b);
+
+ // REAL: Axis value for each dimension's number of values (ca_axis_value)
+ if (isBitSet(readFlags, FLAG_FIXED_AXES)) {
+ List<Double> axisValuesList = new ArrayList<>();
+ for (long i = 0; i < sumNumberOfValuesPerDimension; i++) {
+ axisValuesList.add(MDF4Util.readReal(bb));
+ }
+ block.setAxisValues(axisValuesList);
+ }
+
+ // UINT64: Cycle counts (ca_cycle_count)
+ if (isBitSet(storageTyp, STORAGETYPE_CG_TEMPLATE) || isBitSet(storageTyp, STORAGETYPE_DG_TEMPLATE)) {
+ List<Long> cycleCountsList = new ArrayList<>();
+ for (long i = 0; i < productNumberOfValuesPerDimension; i++) {
+ cycleCountsList.add(MDF4Util.readUInt64(bb));
+ }
+ block.setCycleCounts(cycleCountsList);
+ }
+
+ // extract links after reading data
+
+ int currentLinkIndex = 0;
+ // ca_composition
+ long lnkNestedComposition = lnks[currentLinkIndex++];
+ block.setLnkComposition(lnkNestedComposition);
+ // ca_data
+ if (isBitSet(storageTyp, STORAGETYPE_DG_TEMPLATE)) {
+ List<Long> lnkDataList = new ArrayList<>();
+ for (long i = 0; i < productNumberOfValuesPerDimension; i++) {
+ lnkDataList.add(lnks[currentLinkIndex++]);
+ }
+ block.setLnksData(lnkDataList);
+ }
+ // ca_dynamic_size
+ if (isBitSet(readFlags, FLAG_DYNAMIC_SIZE)) {
+ List<Long> lnkDynamicSizeList = new ArrayList<>();
+ for (long i = 0; i < nrOfDims * 3; i++) {
+ lnkDynamicSizeList.add(lnks[currentLinkIndex++]);
+ }
+ block.setLnksDynamicSize(lnkDynamicSizeList);
+ }
+ // ca_input_quantity
+ if (isBitSet(readFlags, FLAG_INPUT_QUANTITY_DEFINED)) {
+ List<Long> lnkInputQuantityList = new ArrayList<>();
+ for (long i = 0; i < nrOfDims * 3; i++) {
+ lnkInputQuantityList.add(lnks[currentLinkIndex++]);
+ }
+ block.setLnksInputQuantities(lnkInputQuantityList);
+ }
+ // ca_output_quantity
+ if (isBitSet(readFlags, FLAG_OUTPUT_QUANTITY_DEFINED)) {
+ List<Long> lnkOutputQuantityList = new ArrayList<>();
+ for (long i = 0; i < 3; i++) {
+ lnkOutputQuantityList.add(lnks[currentLinkIndex++]);
+ }
+ block.setLnksOutputQuantity(lnkOutputQuantityList);
+ }
+ // ca_comparison_quantity
+ if (isBitSet(readFlags, FLAG_COMPARISON_QUANTITY_DEFINED)) {
+ List<Long> lnkComparisonQuantityList = new ArrayList<>();
+ for (long i = 0; i < 3; i++) {
+ lnkComparisonQuantityList.add(lnks[currentLinkIndex++]);
+ }
+ block.setLnksComparisonQuantity(lnkComparisonQuantityList);
+ }
+ // ca_cc_axis_conversion
+ if (isBitSet(readFlags, FLAG_SCALING_AXIS_DEFINED)) {
+ List<Long> lnkConversionRuleList = new ArrayList<>();
+ for (long i = 0; i < nrOfDims; i++) {
+ lnkConversionRuleList.add(lnks[currentLinkIndex++]);
+ }
+ block.setLnksConversionRule(lnkConversionRuleList);
+ }
+ // ca_axis
+ if (isBitSet(readFlags, FLAG_SCALING_AXIS_DEFINED) && !isBitSet(readFlags, FLAG_FIXED_AXES)) {
+ List<Long> lnkScalingAxisList = new ArrayList<>();
+ for (long i = 0; i < nrOfDims * 3; i++) {
+ lnkScalingAxisList.add(lnks[currentLinkIndex++]);
+ }
+ block.setLnksScalingAxis(lnkScalingAxisList);
+ }
+
+ // throw exception if found unsupported features
+ if (lnkNestedComposition > 0) {
+ throw new IOException("Nested composition is not yet supported! Found at CABlock: [" + block + "]");
+ }
+ if (isBitSet(arrayType, ARRAYTYPE_INTERVAL_AXIS)) {
+ throw new IOException("Array type 'Interval Axis' is not yet supported! Found at CABlock: [" + block + "]");
+ }
+ else if (isBitSet(arrayType, ARRAYTYPE_CLASSIFICATION_RESULT)) {
+ throw new IOException("Array type 'Classification Result' is not yet supported! Found at CABlock: [" + block + "]");
+ }
+ if (isBitSet(storageTyp, STORAGETYPE_CG_TEMPLATE)) {
+ throw new IOException("Storage type 'CG Template' is not yet supported! Found at CABlock: [" + block + "]");
+ }
+ else if (isBitSet(storageTyp, STORAGETYPE_DG_TEMPLATE)) {
+ throw new IOException("Storage type 'DG Template' is not yet supported! Found at CABlock: [" + block + "]");
+ }
+
+ return block;
+ }
+
+ private void setArrayType(byte arrayType) {
+ this.arrayType = arrayType;
+ }
+
+ private void setStorageType(byte storageType) {
+ this.storageType = storageType;
+ }
+
+ private void setNrOfDimensions(int nrOfDimensions) {
+ this.nrOfDimensions = nrOfDimensions;
+ }
+
+ private void setFlags(long flags) {
+ this.flags = flags;
+ }
+
+ private void setByteOffsetBase(long byteOffsetBase) {
+ this.byteOffsetBase = byteOffsetBase;
+ }
+
+ private void setInvalidationBitPositionBase(long invalBitPosBase) {
+ this.invalBitPosBase = invalBitPosBase;
+ }
+
+ private void setDimSizes(List<Long> dimSizesList) {
+ this.dimSizes = dimSizesList.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setAxisValues(List<Double> axisValues) {
+ this.axisValues = axisValues.stream().mapToDouble(i -> i).toArray();
+ }
+
+ private void setCycleCounts(List<Long> cycleCounts) {
+ this.cycleCounts = cycleCounts.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setLnkComposition(long lnkComposition) {
+ this.lnkComposition = lnkComposition;
+ }
+
+ private void setLnksData(List<Long> lnksData) {
+ this.lnksData = lnksData.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setLnksDynamicSize(List<Long> lnksDynamicSize) {
+ this.lnksDynamicSize = lnksDynamicSize.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setLnksInputQuantities(List<Long> lnksInputQuantities) {
+ this.lnksInputQuantity = lnksInputQuantities.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setLnksOutputQuantity(List<Long> lnksOutputQuantity) {
+ this.lnksOutputQuantity = lnksOutputQuantity.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setLnksComparisonQuantity(List<Long> lnksComparisonQuantity) {
+ this.lnksComparisonQuantity = lnksComparisonQuantity.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setLnksConversionRule(List<Long> lnksConversionRule) {
+ this.lnksConversionRule = lnksConversionRule.stream().mapToLong(i -> i).toArray();
+ }
+
+ private void setLnksScalingAxis(List<Long> lnksScalingAxis) {
+ this.lnksScalingAxis = lnksScalingAxis.stream().mapToLong(i -> i).toArray();
+ }
+
+ /**
+ * @return the arrayType
+ */
+ public byte getArrayType()
+ {
+ return arrayType;
+ }
+
+ /**
+ * @return the storageType
+ */
+ public byte getStorageType()
+ {
+ return storageType;
+ }
+
+ /**
+ * @return the flags
+ */
+ public long getFlags()
+ {
+ return flags;
+ }
+
+ /**
+ * @return the byteOffsetBase
+ */
+ public long getByteOffsetBase()
+ {
+ return byteOffsetBase;
+ }
+
+ /**
+ * @return the invalBitPosBase
+ */
+ public long getInvalBitPosBase()
+ {
+ return invalBitPosBase;
+ }
+
+ /**
+ * @return the dimSize for given dimension index
+ */
+ public long getDimSize(int dimIndex)
+ {
+ return dimSizes[dimIndex];
+ }
+
+ /**
+ * @return all value sizes of dimensions
+ */
+ public long[] getDimSizes()
+ {
+ return dimSizes;
+ }
+
+ /**
+ * @return the nrOfDimensions
+ */
+ public int getNrOfDimensions()
+ {
+ return nrOfDimensions;
+ }
+
+ /**
+ * @return the axisValues
+ */
+ public double[] getAxisValues()
+ {
+ return axisValues;
+ }
+
+ /**
+ * @return the cycleCounts
+ */
+ public long[] getCycleCounts()
+ {
+ return cycleCounts;
+ }
+
+ public BLOCK getCompositionBlock() throws IOException
+ {
+ if (lnkComposition > 0) {
+ String blockType = getBlockType(sbc, lnkComposition);
+ BLOCK compositionBlock = null;
+ // link points to a CNBLOCK
+ if (blockType.equals(CNBLOCK.BLOCK_ID)) {
+ compositionBlock = CNBLOCK.read(sbc, lnkComposition);
+ }
+ // link points to CABLOCK
+ else if (blockType.equals(CABLOCK.BLOCK_ID)) {
+ compositionBlock = CABLOCK.read(sbc, lnkComposition);
+ }
+ // unknown
+ else {
+ throw new IOException("Unsupported block type for Composition: " + blockType);
+ }
+
+ throw new IOException("Composition of CABLOCKs is not yet supported! Found the following block: " + compositionBlock);
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the given bitConstant is set in the given bitfield.
+ *
+ * @param bits
+ * @param bitConstant
+ * @return
+ */
+ private static boolean isBitSet(long bits, byte bitConstant) {
+ return (bits & bitConstant) != 0;
+ }
+
+ /**
+ * Returns the requested flag value.
+ *
+ * @param flagConstant one of the flag constants given in this class
+ * @return
+ */
+ public boolean isFlagSet(byte flagConstant) {
+ return (flags & flagConstant) != 0;
+ }
+
+ /**
+ * This method should only be called if the flag FLAG_SCALING_AXIS_DEFINED is
+ * set. If this is true and null is returned here, it
+ *
+ * @param dimIndex
+ * @return
+ */
+ public long getConversionRuleOffsetForDimension(int dimIndex)
+ {
+ if (lnksConversionRule != null && dimIndex < nrOfDimensions && lnksConversionRule.length == 3 * nrOfDimensions)
+ {
+ return lnksConversionRule[nrOfDimensions * 3 - 1];
+ }
+ return -1;
+ }
+
+ /**
+ * This method should only be called if the flag FLAG_SCALING_AXIS_DEFINED is
+ * set and FLAG_FIXED_AXIS is not set.
+ *
+ * @param dimIndex
+ * the index of the dimension to get the scaling axis offsets for
+ * @return a {@link BlockReferenceTriple} containing the offsets to read the
+ * CNBLOCK defining the scaling axis for the dimension with the
+ * given index or null if none defined
+ */
+ public BlockReferenceTriple getScalingAxisOffsetsForDimension(int dimIndex)
+ {
+ return createReferenceTriple(dimIndex, lnksScalingAxis);
+ }
+
+ /**
+ * This method should only be called if the flag FLAG_INPUT_QUANTITY_DEFINED
+ * is set.
+ *
+ * @param dimIndex
+ * the index of the dimension to get the input quantity offsets for
+ * @return a {@link BlockReferenceTriple} containing the offsets to read the
+ * CNBLOCK defining the input quantity for the dimension with the
+ * given index or null if none defined
+ */
+ public BlockReferenceTriple getInputQuantityOffsetsForDimension(int dimIndex)
+ {
+ return createReferenceTriple(dimIndex, lnksInputQuantity);
+ }
+
+ /**
+ * This method should only be called if the flag FLAG_OUTPUR_QUANTITY_DEFINED
+ * is set.
+ *
+ * @param dimIndex
+ * the index of the dimension to get the output quantity offsets for
+ * @return a {@link BlockReferenceTriple} containing the offsets to read the
+ * CNBLOCK defining the output quantity for the dimension with the
+ * given index or null if none defined
+ */
+ public BlockReferenceTriple getOutputQuantityOffsetsForDimension(int dimIndex)
+ {
+ return createReferenceTriple(dimIndex, lnksOutputQuantity);
+ }
+
+ /**
+ * This method should only be called if the flag
+ * FLAG_COMPARISON_QUANTITY_DEFINED is set.
+ *
+ * @param dimIndex
+ * the index of the dimension to get the comparison quantity offsets
+ * for
+ * @return a {@link BlockReferenceTriple} containing the offsets to read the
+ * CNBLOCK defining the comparison quantity for the dimension with the
+ * given index or null if none defined
+ */
+ public BlockReferenceTriple getComparisonQuantityOffsetsForDimension(int dimIndex)
+ {
+ return createReferenceTriple(dimIndex, lnksComparisonQuantity);
+ }
+
+ /**
+ * This method should only be called if the flag FLAG_DYNAMIC_SIZE is set.
+ *
+ * @param dimIndex
+ * the index of the dimension to get the dynamic size signal offsets
+ * for
+ * @return a {@link BlockReferenceTriple} containing the offsets to read the
+ * CNBLOCK defining the dynamic size signal for the dimension with the
+ * given index or null if none defined
+ */
+ public BlockReferenceTriple getSizeSignalOffsetsForDimension(int dimIndex)
+ {
+ return createReferenceTriple(dimIndex, lnksDynamicSize);
+ }
+
+ /**
+ * Creates a {@link BlockReferenceTriple} from the given offsets for the given
+ * dimension index.
+ *
+ * @param dimIndex
+ * the index of the dimension to get the offset triple for
+ * @param offsets
+ * the offset structure to read from
+ * @return a {@link BlockReferenceTriple} containing the requested offsets or
+ * null if none defined
+ */
+ private BlockReferenceTriple createReferenceTriple(int dimIndex, long[] offsets)
+ {
+ if (offsets != null && dimIndex < nrOfDimensions && offsets.length == 3 * nrOfDimensions)
+ {
+ return new BlockReferenceTriple(offsets[dimIndex * 3 + 0], offsets[dimIndex * 3 + 1], offsets[dimIndex * 3 + 2]);
+ }
+ return null;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ *
+ * @return
+ */
+ @Override
+ public String toString()
+ {
+ return "CABLOCK [lnkComposition=" + lnkComposition + ", lnksData=" + Arrays.toString(lnksData)
+ + ", lnksDynamicSize=" + Arrays.toString(lnksDynamicSize) + ", lnksInputQuantities="
+ + Arrays.toString(lnksInputQuantity) + ", lnksOutputQuantity=" + Arrays.toString(lnksOutputQuantity)
+ + ", lnksComparisonQuantity=" + Arrays.toString(lnksComparisonQuantity) + ", lnksScalingAxis="
+ + Arrays.toString(lnksConversionRule) + ", lnksAxis=" + Arrays.toString(lnksScalingAxis) + ", arrayType=" + arrayType
+ + ", storageType=" + storageType + ", flags=" + flags + ", byteOffsetBase=" + byteOffsetBase
+ + ", invalBitPosBase=" + invalBitPosBase + ", dimSizes=" + Arrays.toString(dimSizes) + ", nrOfDimensions="
+ + nrOfDimensions + ", axisValues=" + Arrays.toString(axisValues) + ", cycleCounts="
+ + Arrays.toString(cycleCounts) + "]";
+ }
+}
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CCBLOCK.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CCBLOCK.java
index 4401cae..3099d0f 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CCBLOCK.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CCBLOCK.java
@@ -121,7 +121,9 @@
// List of additional conversion parameters.
// Length of list is given by cc_val_count. The list can be empty.
// REAL N
- private double[] val;
+ private double[] val;
+
+ private CCBLOCK defaultValueBlock;
/**
* Constructor.
@@ -306,17 +308,15 @@
TXBLOCK[] ccRef = new TXBLOCK[lnkCcRef.length];
for (int i = 0; i < ccRef.length; i++) {
if (lnkCcRef[i] > 0) {
- // There might be a CC Block, but this is not supported.
-
String blockType = getBlockType(sbc, lnkCcRef[i]);
// link points to a TXBLOCK
if (blockType.equals(TXBLOCK.BLOCK_ID)) {
ccRef[i] = TXBLOCK.read(sbc, lnkCcRef[i]);
}
- // links points to CCBLOCK
- else if (blockType.equals(CCBLOCK.BLOCK_ID)) {
- throw new IOException("Scale conversions with CCBlocks are not supported.");
- }
+ // link points to CCBLOCK containing formula for default value
+ else if (blockType.equals(CCBLOCK.BLOCK_ID) && defaultValueBlock == null) {
+ defaultValueBlock = CCBLOCK.read(sbc, lnkCcRef[i]);
+ }
// unknown
else {
throw new IOException("Unsupported block type for Conversion Reference: " + blockType);
@@ -514,12 +514,14 @@
}
}
- /**
- * Returns the default value for this conversion.
- *
- * @return The default value.
- * @throws IOException
- */
+ /**
+ * Returns the default value for this conversion. For types 7, 8 and 10 the
+ * default value is specified at last cc_ref value and it may be not defined,
+ * if no default value is available.
+ *
+ * @return The default value.
+ * @throws IOException
+ */
public String getDefaultValue() throws IOException {
if (type == 7 || type == 8 || type == 10) {
long lnkLastRef = lnkCcRef[getRefCount() - 1];
@@ -529,14 +531,17 @@
// link points to a TXBLOCK, return content.
if (blockType.equals(TXBLOCK.BLOCK_ID)) {
return TXBLOCK.read(sbc, lnkLastRef).getTxData();
- }
- // links points to CCBLOCK
- else if (blockType.equals(CCBLOCK.BLOCK_ID)) {
- throw new IOException("Scale conversions with CCBlocks are not supported.");
- }
- // unknown
+ }
+ // link points to CCBLOCK
+ else if (blockType.equals(CCBLOCK.BLOCK_ID)) {
+ if (defaultValueBlock == null) {
+ defaultValueBlock = CCBLOCK.read(sbc, lnkLastRef);
+ }
+// throw new IOException("Scale conversions with CCBlocks are not supported by ASAM ODS.");
+ }
+ // unknown
else {
- throw new IOException("Unsupported block type for Conversion Reference: " + blockType);
+ throw new IOException("Unsupported block type for Default Value Conversion Reference: " + blockType);
}
}
}
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CNBLOCK.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CNBLOCK.java
index 8ae8940..6d7b3e1 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CNBLOCK.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/CNBLOCK.java
@@ -553,6 +553,31 @@
}
return null;
}
+
+ /**
+ * Returns the CA- or CN-block, linked by the composition link.
+ *
+ * @return
+ * @throws IOException
+ */
+ public BLOCK getCompositionBlock() throws IOException {
+ if (lnkComposition > 0) {
+ String blockType = getBlockType(sbc, lnkComposition);
+ // link points to a CNBLOCK
+ if (blockType.equals(CNBLOCK.BLOCK_ID)) {
+ return CNBLOCK.read(sbc, lnkComposition);
+ }
+ // link points to CABLOCK
+ else if (blockType.equals(CABLOCK.BLOCK_ID)) {
+ return CABLOCK.read(sbc, lnkComposition);
+ }
+ // unknown
+ else {
+ throw new IOException("Unsupported block type for Composition: " + blockType);
+ }
+ }
+ return null;
+ }
@Override
public String toString() {
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/ChannelReader.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/ChannelReader.java
new file mode 100644
index 0000000..56c66e2
--- /dev/null
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/ChannelReader.java
@@ -0,0 +1,241 @@
+package org.eclipse.mdm.openatfx.mdf.mdf4;
+
+import java.io.IOException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class ChannelReader
+{
+ private static final Log LOG = LogFactory.getLog(ChannelReader.class);
+ private static final int MAX_BUFFER_SIZE = 2048;
+ private final DGBLOCK dgBlock;
+ private final CGBLOCK cgBlock;
+ private final CNBLOCK cnBlock;
+
+ public ChannelReader(String mdfPath, long dgOffset, long cgOffset, long cnOffset)
+ {
+ SeekableByteChannel sbc;
+ try
+ {
+ sbc = Files.newByteChannel(Paths.get(mdfPath), StandardOpenOption.READ);
+ dgBlock = DGBLOCK.read(sbc, dgOffset);
+ cgBlock = CGBLOCK.read(sbc, cgOffset);
+ cnBlock = CNBLOCK.read(sbc, cnOffset);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error reading from mdf file: " + e.getLocalizedMessage());
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ if (args.length != 4)
+ {
+ LOG.error("Wrong arguments: Must be called with the mdf filepath and the offsets for DGBLOCK, CGBLOCK and CNBLOCK!");
+ }
+ else
+ {
+ String mdfPath = null;
+ long dgOffset = -1;
+ long cgOffset = -1;
+ long cnOffset = -1;
+ for (int i = 0; i < 4; i++)
+ {
+ String arg = args[i];
+ switch (i)
+ {
+ case 0:
+ mdfPath = arg.trim();
+ break;
+
+ case 1:
+ dgOffset = Long.valueOf(arg);
+ break;
+
+ case 2:
+ cgOffset = Long.valueOf(arg);
+ break;
+
+ case 3:
+ cnOffset = Long.valueOf(arg);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ChannelReader reader = new ChannelReader(mdfPath, dgOffset, cgOffset, cnOffset);
+ try
+ {
+ LOG.info(reader.readValues());
+ }
+ catch (IOException e)
+ {
+ LOG.error("Error reading channel values: " + e.getLocalizedMessage());
+ }
+ }
+ }
+
+ public String readValues() throws IOException
+ {
+ DTBLOCK dataBlock = DTBLOCK.read(dgBlock.sbc, dgBlock.getLnkData());
+ long startDataOffset = dgBlock.getLnkData() + 24; // header of DTBLOCK is 24 bytes long
+ long dataBlockLength = dataBlock.getLength();
+
+ long position = dgBlock.getLnkData() + 24 + cnBlock.getByteOffset();
+ switch (cnBlock.getDataType())
+ {
+ case 0:
+ List<Long> values0 = readIntsFromByteChannel(true, true, (int)cnBlock.getBitCount(), cnBlock.sbc, position, (int)cgBlock.getCycleCount());
+ return values0.stream().map(String::valueOf).collect(Collectors.joining(", "));
+ case 1:
+ List<Long> values1 = readIntsFromByteChannel(true, false, (int)cnBlock.getBitCount(), cnBlock.sbc, position, (int)cgBlock.getCycleCount());
+ return values1.stream().map(String::valueOf).collect(Collectors.joining(", "));
+ case 2:
+ List<Long> values2 = readIntsFromByteChannel(false, true, (int)cnBlock.getBitCount(), cnBlock.sbc, position, (int)cgBlock.getCycleCount());
+ return values2.stream().map(String::valueOf).collect(Collectors.joining(", "));
+ case 3:
+ List<Long> values3 = readIntsFromByteChannel(false, false, (int)cnBlock.getBitCount(), cnBlock.sbc, position, (int)cgBlock.getCycleCount());
+ return values3.stream().map(String::valueOf).collect(Collectors.joining(", "));
+ case 4:
+ List<Double> values4 = readRealsFromByteChannel(cnBlock.sbc, true, position, (int)cgBlock.getCycleCount());
+ return values4.stream().map(String::valueOf).collect(Collectors.joining(", "));
+ case 5:
+ List<Double> values5 = readRealsFromByteChannel(cnBlock.sbc, false, position, (int)cgBlock.getCycleCount());
+ return values5.stream().map(String::valueOf).collect(Collectors.joining(", "));
+ default:
+ throw new RuntimeException("readValues() not supported yet for String or complex datatypes!");
+ }
+ }
+
+ public List<Long> readIntsFromByteChannel(boolean unsigned, boolean littleEndian, int bits, SeekableByteChannel channel, long pos, int readCount) throws IOException
+ {
+ ByteBuffer bb = ByteBuffer.allocate(bits / 8 * readCount);
+ if (littleEndian)
+ {
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ }
+ else
+ {
+ bb.order(ByteOrder.BIG_ENDIAN);
+ }
+ channel.position(pos);
+ channel.read(bb);
+ bb.rewind();
+
+ List<Long> readValues = new ArrayList<>();
+ for (int i = 0; i < readCount; i++)
+ {
+ switch (bits)
+ {
+ case 8:
+ readValues.add((long) MDF4Util.readUInt8(bb));
+ break;
+ case 16:
+ if (unsigned)
+ {
+ readValues.add((long) MDF4Util.readUInt16(bb));
+ }
+ else
+ {
+ readValues.add((long) MDF4Util.readInt16(bb));
+ }
+ break;
+ case 32:
+ if (unsigned)
+ {
+ readValues.add(MDF4Util.readUInt32(bb));
+ }
+ else
+ {
+ readValues.add((long) MDF4Util.readInt32(bb));
+ }
+ break;
+ case 64:
+ if (unsigned)
+ {
+ readValues.add(MDF4Util.readUInt64(bb));
+ }
+ else
+ {
+ readValues.add(MDF4Util.readInt64(bb));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return readValues;
+ }
+
+ public List<Double> readRealsFromByteChannel(SeekableByteChannel channel, boolean littleEndian, long pos, int readCount) throws IOException
+ {
+ ByteBuffer bb = ByteBuffer.allocate(8 * readCount);
+ if (littleEndian)
+ {
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ }
+ else
+ {
+ bb.order(ByteOrder.BIG_ENDIAN);
+ }
+ channel.position(pos);
+ channel.read(bb);
+ bb.rewind();
+
+ List<Double> readValues = new ArrayList<>();
+ for (int i = 0; i < readCount; i++)
+ {
+ readValues.add(MDF4Util.readReal(bb));
+ }
+
+ return readValues;
+ }
+
+ public void temp(short bitCount, short bitOffset, ByteBuffer sourceMbb)
+ {
+ // read that number of bytes from the byte position within the file
+ int bytesToRead = ((bitCount + bitOffset - 1) / 8) + 1;
+ byte[] tmp = new byte[bytesToRead];
+ sourceMbb.get(tmp);
+
+ // put the byte into an integer to enable bit shifting
+ if (tmp.length <= 4) {
+ ByteBuffer bb = ByteBuffer.allocate(4);
+ bb.order(sourceMbb.order());
+ bb.put(tmp);
+ Buffer.class.cast(bb).rewind(); // workaround: make buildable with both java8 and java9
+ int intValue = bb.getInt();
+ intValue = intValue >> bitOffset; // shift right bit offset
+ int mask = 0xFFFFFFFF >>> (32 - bitCount); // mask out unnecessary bits
+ intValue = intValue & mask;
+// list.add(intValue);
+ }
+ // put the byte into a long to enable bit shifting
+ else {
+ ByteBuffer bb = ByteBuffer.allocate(8);
+ bb.order(sourceMbb.order());
+ bb.put(tmp);
+ Buffer.class.cast(bb).rewind(); // workaround: make buildable with both java8 and java9
+ long longValue = bb.getLong();
+ longValue = longValue >> bitOffset; // shift right bit offset
+ long mask = 0xFFFFFFFFFFFFFFFFl >>> (64 - bitCount); // mask out unnecessary bits
+ longValue = longValue & mask;
+// list.add(longValue);
+ }
+ }
+}
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/MDF4Util.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/MDF4Util.java
index 10f8be1..d181986 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/MDF4Util.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/MDF4Util.java
@@ -15,15 +15,15 @@
package org.eclipse.mdm.openatfx.mdf.mdf4;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import org.eclipse.mdm.openatfx.mdf.util.ODSHelper;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.eclipse.mdm.openatfx.mdf.util.ODSHelper;
import org.eclipse.mdm.openatfx.mdf.util.ODSInsertStatement;
/**
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/PreviewHelper.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/PreviewHelper.java
index 1348eb8..cf18fba 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/PreviewHelper.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/mdf4/PreviewHelper.java
@@ -11,211 +11,211 @@
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
-
-
-package org.eclipse.mdm.openatfx.mdf.mdf4;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.asam.ods.AoException;
-import org.asam.ods.InstanceElement;
-import org.asam.ods.InstanceElementIterator;
-import org.asam.ods.Relationship;
-import org.eclipse.mdm.openatfx.mdf.util.ODSHelper;
-import org.eclipse.mdm.openatfx.mdf.util.ODSInsertStatement;
-import org.eclipse.mdm.openatfx.mdf.util.ODSModelCache;
-
-/**
- * Helper class to convert Sample Reduction blocks to a ASAM ODS
- * 'AoMeasurement'.
- *
- * @author Tobias Leemann
- */
-class PreviewHelper {
-
- // the cached lookup instance element
- private long previewMeaiid = Long.MIN_VALUE;
- private ODSModelCache cache;
- private AoSessionWriter writer;
-
- // The SRBLOCKs used.
- private SRBLOCK[] srBlocks;
-
- // The smIids in use.
- private Long[] smIids;
-
- private Map<String, Long> meqInstances = new HashMap<String, Long>();
-
- private int generationCount = 0;
-
- public synchronized void setCache(ODSModelCache cache) {
- this.cache = cache;
- }
-
- public synchronized void setWriter(AoSessionWriter writer) {
- this.writer = writer;
- }
-
- /**
- * Creates a preview Measurment if none exists.
- *
- * @param ieMea
- * The InstanceElement of the Main Measurement
- * @throws AoException
- * If an ASAM ODS error occurs.
- */
- private synchronized void createMeasurementIfNeeded(InstanceElement ieMea) throws AoException {
- // create 'AoMeasurement' instance (if not yet existing)
- if (previewMeaiid == Long.MIN_VALUE) {
- // lookup parent 'AoTest' instance
- InstanceElementIterator iter = ieMea.getRelatedInstancesByRelationship(Relationship.FATHER, "*");
- InstanceElement ieTst = iter.nextOne();
- iter.destroy();
- String meaName = ieMea.getName() + "_previews";
- ODSInsertStatement ins = new ODSInsertStatement(cache, "mea");
- ins.setStringVal("iname", meaName);
- ins.setStringVal("mt", "application/x-asam.aomeasurement.mdf_preview");
- ins.setNameValueUnit(ieMea.getValue("date_created"));
- ins.setNameValueUnit(ieMea.getValue("mea_begin"));
- ins.setNameValueUnit(ieMea.getValue("mea_end"));
- ins.setLongLongVal("tst", ODSHelper.asJLong(ieTst.getId()));
- previewMeaiid = ins.execute();
- }
- }
-
- /**
- * Creates Previews for a Channel in all SubMatrix elements created by
- * createPreviewSubMatrices. This method must be invoked after
- * createPreviewSubMatrices.
- *
- * @param channelName
- * The name of the Channel the preview will be created for.
- * @param idBlock
- * The IDBLOCK.
- * @param cgBlock
- * The CGBLOCK of the Channel.
- * @param dgBlock
- * The DGBLOCK of the Channel.
- * @param cnBlock
- * The CNBLOCK of this Channel.
- * @param ccBlock
- * The CCBLOCK of the Channel.
- * @param untInstances
- * MapContaining all existing Units.
- * @throws AoException
- * @throws IOException
- */
- public synchronized void createPreviewChannels(String channelName, IDBLOCK idBlock, CGBLOCK cgBlock,
- DGBLOCK dgBlock, CNBLOCK cnBlock, CCBLOCK ccBlock, Map<String, Long> untInstances)
- throws AoException, IOException {
- if (smIids == null) {
- throw new IOException("Preview IIDS not set.");
- }
- if (srBlocks == null) {
- throw new IOException("Preview srBlocks not set.");
- }
- if (writer == null) {
- throw new IOException("Preview writer not set.");
- }
- String[] nameExtensions = { "average", "maximum", "minimum" };
- for (int reductionNo = 0; reductionNo < srBlocks.length; reductionNo++) {
- for (int i = 0; i < 3; i++) {
- String extendedName = channelName + "_" + nameExtensions[i];
- // create MeasurmentQuantity if needed
- Long iidMeq = meqInstances.get(extendedName);
- if (iidMeq == null) {
- iidMeq = writer.createMeasurementQuantity(cache, cnBlock, ccBlock, extendedName, previewMeaiid,
- "application/x-asam.aomeasurementquantity.mdf_preview." + nameExtensions[i], untInstances);
- meqInstances.put(extendedName, iidMeq);
- }
- // create AoLocalColumns
- long iidLc = writer.createLocalColumn(cache, dgBlock, cgBlock, cnBlock, ccBlock, extendedName,
- smIids[reductionNo], iidMeq, null,
- "application/x-asam.aolocalcolumn.mdf_preview." + nameExtensions[i]);
-
- // create AoExternalComponents
- writer.writeEc(cache, iidLc, idBlock, dgBlock, cgBlock, cnBlock, ccBlock,
- srBlocks[reductionNo].getLnkRdData(), i + 1);
- }
- }
-
- }
-
- /**
- * Create SubMatices for all SRBLOCKs linked from <code>srBlock</code> This
- * method must be called before <code>createPreviewChannels()</code>.
- *
- * @param ieMea
- * The instance element of the main Measurement.
- * @param srBlock
- * The first SRBLOCK in the list.
- * @return The IDs of the created SubMatrix elements.
- * @throws AoException
- * @throws IOException
- */
- public synchronized long[] createPreviewSubMatrices(InstanceElement ieMea, SRBLOCK srBlock)
- throws AoException, IOException {
- if (srBlock == null) {
- return null;
- // nothing to do
- }
-
- createMeasurementIfNeeded(ieMea);
-
- // create AoSubMatrix instance
- LinkedList<SRBLOCK> srBlocks = new LinkedList<SRBLOCK>();
- LinkedList<Long> iids = new LinkedList<Long>();
- while (srBlock != null) {
- ODSInsertStatement ins = new ODSInsertStatement(cache, "sm");
- ins.setStringVal("iname", getPrevName(srBlock));
- ins.setStringVal("mt", "application/x-asam.aosubmatrix.mdf_preview");
- ins.setLongVal("rows", (int) srBlock.getCycleCount());
- ins.setLongLongVal("mea", previewMeaiid);
- long smIid = ins.execute();
- srBlocks.add(srBlock);
- iids.add(smIid);
- srBlock = srBlock.getSrNextBlock();
- }
- this.srBlocks = srBlocks.toArray(new SRBLOCK[0]);
- smIids = iids.toArray(new Long[0]);
- generationCount++;
- long[] ret = new long[smIids.length];
- for (int i = 0; i < smIids.length; i++) {
- ret[i] = smIids[i];
- }
- return ret;
- }
-
- /**
- * Create a unique Channel name from an SRBLOCK.
- *
- * @param srBlock
- * The SRBLOCK
- * @return The name.
- */
- private String getPrevName(SRBLOCK srBlock) {
- String ret = "reduction_group" + generationCount + "_";
- ret += String.valueOf(srBlock.getInterval());
- switch (srBlock.getSyncType()) {
- case 1:
- ret += "s";
- break;
- case 2:
- ret += "rad";
- break;
- case 3:
- ret += "m";
- break;
- case 4:
- ret += "records";
- break;
- default:
- break;
- }
- return ret;
- }
-
-}
+
+
+package org.eclipse.mdm.openatfx.mdf.mdf4;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.asam.ods.AoException;
+import org.asam.ods.InstanceElement;
+import org.asam.ods.InstanceElementIterator;
+import org.asam.ods.Relationship;
+import org.eclipse.mdm.openatfx.mdf.util.ODSHelper;
+import org.eclipse.mdm.openatfx.mdf.util.ODSInsertStatement;
+import org.eclipse.mdm.openatfx.mdf.util.ODSModelCache;
+
+/**
+ * Helper class to convert Sample Reduction blocks to a ASAM ODS
+ * 'AoMeasurement'.
+ *
+ * @author Tobias Leemann
+ */
+class PreviewHelper {
+
+ // the cached lookup instance element
+ private long previewMeaiid = Long.MIN_VALUE;
+ private ODSModelCache cache;
+ private AoSessionWriter writer;
+
+ // The SRBLOCKs used.
+ private SRBLOCK[] srBlocks;
+
+ // The smIids in use.
+ private Long[] smIids;
+
+ private Map<String, Long> meqInstances = new HashMap<String, Long>();
+
+ private int generationCount = 0;
+
+ public synchronized void setCache(ODSModelCache cache) {
+ this.cache = cache;
+ }
+
+ public synchronized void setWriter(AoSessionWriter writer) {
+ this.writer = writer;
+ }
+
+ /**
+ * Creates a preview Measurment if none exists.
+ *
+ * @param ieMea
+ * The InstanceElement of the Main Measurement
+ * @throws AoException
+ * If an ASAM ODS error occurs.
+ */
+ private synchronized void createMeasurementIfNeeded(InstanceElement ieMea) throws AoException {
+ // create 'AoMeasurement' instance (if not yet existing)
+ if (previewMeaiid == Long.MIN_VALUE) {
+ // lookup parent 'AoTest' instance
+ InstanceElementIterator iter = ieMea.getRelatedInstancesByRelationship(Relationship.FATHER, "*");
+ InstanceElement ieTst = iter.nextOne();
+ iter.destroy();
+ String meaName = ieMea.getName() + "_previews";
+ ODSInsertStatement ins = new ODSInsertStatement(cache, "mea");
+ ins.setStringVal("iname", meaName);
+ ins.setStringVal("mt", "application/x-asam.aomeasurement.mdf_preview");
+ ins.setNameValueUnit(ieMea.getValue("date_created"));
+ ins.setNameValueUnit(ieMea.getValue("mea_begin"));
+ ins.setNameValueUnit(ieMea.getValue("mea_end"));
+ ins.setLongLongVal("tst", ODSHelper.asJLong(ieTst.getId()));
+ previewMeaiid = ins.execute();
+ }
+ }
+
+ /**
+ * Creates Previews for a Channel in all SubMatrix elements created by
+ * createPreviewSubMatrices. This method must be invoked after
+ * createPreviewSubMatrices.
+ *
+ * @param channelName
+ * The name of the Channel the preview will be created for.
+ * @param idBlock
+ * The IDBLOCK.
+ * @param cgBlock
+ * The CGBLOCK of the Channel.
+ * @param dgBlock
+ * The DGBLOCK of the Channel.
+ * @param cnBlock
+ * The CNBLOCK of this Channel.
+ * @param ccBlock
+ * The CCBLOCK of the Channel.
+ * @param untInstances
+ * MapContaining all existing Units.
+ * @throws AoException
+ * @throws IOException
+ */
+ public synchronized void createPreviewChannels(String channelName, IDBLOCK idBlock, CGBLOCK cgBlock,
+ DGBLOCK dgBlock, CNBLOCK cnBlock, CCBLOCK ccBlock, Map<String, Long> untInstances)
+ throws AoException, IOException {
+ if (smIids == null) {
+ throw new IOException("Preview IIDS not set.");
+ }
+ if (srBlocks == null) {
+ throw new IOException("Preview srBlocks not set.");
+ }
+ if (writer == null) {
+ throw new IOException("Preview writer not set.");
+ }
+ String[] nameExtensions = { "average", "maximum", "minimum" };
+ for (int reductionNo = 0; reductionNo < srBlocks.length; reductionNo++) {
+ for (int i = 0; i < 3; i++) {
+ String extendedName = channelName + "_" + nameExtensions[i];
+ // create MeasurmentQuantity if needed
+ Long iidMeq = meqInstances.get(extendedName);
+ if (iidMeq == null) {
+ iidMeq = writer.createMeasurementQuantity(cache, cnBlock, ccBlock, null, extendedName, previewMeaiid,
+ "application/x-asam.aomeasurementquantity.mdf_preview." + nameExtensions[i], untInstances);
+ meqInstances.put(extendedName, iidMeq);
+ }
+ // create AoLocalColumns
+ long iidLc = writer.createLocalColumn(cache, dgBlock, cgBlock, cnBlock, ccBlock, null, extendedName,
+ smIids[reductionNo], -1, iidMeq, null,
+ "application/x-asam.aolocalcolumn.mdf_preview." + nameExtensions[i]);
+
+ // create AoExternalComponents
+ writer.writeEc(cache, iidLc, idBlock, dgBlock, cgBlock, cnBlock, ccBlock, null,
+ srBlocks[reductionNo].getLnkRdData(), i + 1);
+ }
+ }
+
+ }
+
+ /**
+ * Create SubMatices for all SRBLOCKs linked from <code>srBlock</code> This
+ * method must be called before <code>createPreviewChannels()</code>.
+ *
+ * @param ieMea
+ * The instance element of the main Measurement.
+ * @param srBlock
+ * The first SRBLOCK in the list.
+ * @return The IDs of the created SubMatrix elements.
+ * @throws AoException
+ * @throws IOException
+ */
+ public synchronized long[] createPreviewSubMatrices(InstanceElement ieMea, SRBLOCK srBlock)
+ throws AoException, IOException {
+ if (srBlock == null) {
+ return null;
+ // nothing to do
+ }
+
+ createMeasurementIfNeeded(ieMea);
+
+ // create AoSubMatrix instance
+ LinkedList<SRBLOCK> srBlocks = new LinkedList<SRBLOCK>();
+ LinkedList<Long> iids = new LinkedList<Long>();
+ while (srBlock != null) {
+ ODSInsertStatement ins = new ODSInsertStatement(cache, "sm");
+ ins.setStringVal("iname", getPrevName(srBlock));
+ ins.setStringVal("mt", "application/x-asam.aosubmatrix.mdf_preview");
+ ins.setLongVal("rows", (int) srBlock.getCycleCount());
+ ins.setLongLongVal("mea", previewMeaiid);
+ long smIid = ins.execute();
+ srBlocks.add(srBlock);
+ iids.add(smIid);
+ srBlock = srBlock.getSrNextBlock();
+ }
+ this.srBlocks = srBlocks.toArray(new SRBLOCK[0]);
+ smIids = iids.toArray(new Long[0]);
+ generationCount++;
+ long[] ret = new long[smIids.length];
+ for (int i = 0; i < smIids.length; i++) {
+ ret[i] = smIids[i];
+ }
+ return ret;
+ }
+
+ /**
+ * Create a unique Channel name from an SRBLOCK.
+ *
+ * @param srBlock
+ * The SRBLOCK
+ * @return The name.
+ */
+ private String getPrevName(SRBLOCK srBlock) {
+ String ret = "reduction_group" + generationCount + "_";
+ ret += String.valueOf(srBlock.getInterval());
+ switch (srBlock.getSyncType()) {
+ case 1:
+ ret += "s";
+ break;
+ case 2:
+ ret += "rad";
+ break;
+ case 3:
+ ret += "m";
+ break;
+ case 4:
+ ret += "records";
+ break;
+ default:
+ break;
+ }
+ return ret;
+ }
+
+}
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSHelper.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSHelper.java
index 097b5d6..d50568a 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSHelper.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSHelper.java
@@ -11,772 +11,772 @@
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
-
-
-package org.eclipse.mdm.openatfx.mdf.util;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.asam.ods.NameValue;
-import org.asam.ods.NameValueUnit;
-import org.asam.ods.TS_Union;
-import org.asam.ods.TS_Value;
-import org.asam.ods.T_DCOMPLEX;
-import org.asam.ods.T_ExternalReference;
-import org.asam.ods.T_LONGLONG;
-
-/**
- * Helper class with ODS specific functions.
- *
- * @author Christian Rechner
- */
-public abstract class ODSHelper {
-
- // prepare dateformats to avoid instantiation a single object every time
- // parsing a date.
- private static Map<Integer, DateFormat> ODS_DATEFORMATS = new HashMap<Integer, DateFormat>();
- static {
- ODS_DATEFORMATS.put(4, new SimpleDateFormat("yyyy"));
- ODS_DATEFORMATS.put(6, new SimpleDateFormat("yyyyMM"));
- ODS_DATEFORMATS.put(8, new SimpleDateFormat("yyyyMMdd"));
- ODS_DATEFORMATS.put(10, new SimpleDateFormat("yyyyMMddHH"));
- ODS_DATEFORMATS.put(12, new SimpleDateFormat("yyyyMMddHHmm"));
- ODS_DATEFORMATS.put(14, new SimpleDateFormat("yyyyMMddHHmmss"));
- ODS_DATEFORMATS.put(17, new SimpleDateFormat("yyyyMMddHHmmssSSS"));
- }
-
- /**
- * Return an ODS date from a <code>java.util.Date</code>.
- *
- * @param date
- * the <code>java.util.Date</code> to convert
- * @return the date in ODS date-format (YYYYMMDDhhmmss)
- */
- public static synchronized String asODSDate(Date date) {
- if (date == null) {
- return "";
- }
- return ODS_DATEFORMATS.get(14).format(date);
- }
-
- /**
- * Returns the java date from an ODS date.
- *
- * @param odsDate
- * the ODS date string
- * @return the java <code>java.util.Date</code> object, null if empty date
- * @throws IllegalArgumentException
- * unable to parse
- */
- public static synchronized Date asJDate(String odsDate) {
- try {
- if (odsDate == null || odsDate.length() < 1) {
- return null;
- }
- DateFormat format = ODS_DATEFORMATS.get(odsDate.length());
- if (format == null) {
- throw new IllegalArgumentException("Invalid ODS date: " + odsDate);
- }
- return format.parse(odsDate);
- } catch (ParseException e) {
- throw new IllegalArgumentException("Invalid ODS date: " + odsDate);
- }
- }
-
- /**
- * Returns a Java long from ODS T_LONGLONG.
- *
- * @param ll
- * ODS T_LONGLONG value
- * @return Java long with the same value as ll
- */
- public static long asJLong(T_LONGLONG ll) {
- long tmp;
- if (ll.low >= 0) {
- tmp = ll.high * 0x100000000L + ll.low;
- } else {
- tmp = (ll.high + 1) * 0x100000000L + ll.low;
- }
- return tmp;
- }
-
- /**
- * Returns an array of Java long from ODS T_LONGLONG.
- *
- * @param ll
- * array of ODS T_LONGLONG values
- * @return array of Java long values
- */
- public static long[] asJLong(T_LONGLONG[] ll) {
- long[] ar = new long[ll.length];
- for (int i = 0; i < ll.length; i++) {
- ar[i] = asJLong(ll[i]);
- }
- return ar;
- }
-
- /**
- * Return ODS T_LONGLONG from Java long.
- *
- * @param v
- * Java long value
- * @return ODS T_LONGLONG with the same value as v
- */
- public static T_LONGLONG asODSLongLong(long v) {
- return new T_LONGLONG((int) (v >> 32 & 0xffffffffL), (int) (v & 0xffffffffL));
- }
-
- /**
- * Returns an array of ODS T_LONGLONG from Java longs.
- *
- * @param v
- * array of Java long values
- * @return array of ODS T_LONGLONG values
- */
- public static T_LONGLONG[] asODSLongLong(long[] v) {
- T_LONGLONG[] ar = new T_LONGLONG[v.length];
- for (int i = 0; i < v.length; i++) {
- ar[i] = asODSLongLong(v[i]);
- }
- return ar;
- }
-
- public static String getCurrentODSDate() {
- return asODSDate(new Date());
- }
-
- private static NameValue createNV(String valName, TS_Union union) {
- NameValue nv = new NameValue();
- nv.valName = valName;
- nv.value = new TS_Value();
- nv.value.flag = 15;
- nv.value.u = union;
- return nv;
- }
-
- private static NameValueUnit createNVU(String attrName, TS_Union union) {
- NameValueUnit nvu = new NameValueUnit();
- nvu.valName = attrName;
- nvu.value = new TS_Value();
- nvu.unit = "";
- nvu.value.flag = 15;
- nvu.value.u = union;
- return nvu;
- }
-
- private static NameValueUnit createNVU(String attrName, TS_Union union, String unit) {
- NameValueUnit nvu = new NameValueUnit();
- nvu.valName = attrName;
- nvu.value = new TS_Value();
- nvu.value.u = new TS_Union();
- nvu.unit = unit;
- nvu.value.flag = 15;
- nvu.value.u = union;
- return nvu;
- }
-
- public static NameValueUnit createCurrentDateNVU(String attrName) {
- TS_Union union = new TS_Union();
- union.dateVal(getCurrentODSDate());
- return createNVU(attrName, union);
- }
-
- public static NameValue createStringNV(String valName, String value) {
- NameValue nv = new NameValue();
- nv.valName = valName;
- nv.value = new TS_Value();
- nv.value.u = new TS_Union();
- if (value == null) {
- nv.value.flag = 0;
- nv.value.u.stringVal("");
- } else {
- nv.value.flag = 15;
- nv.value.u.stringVal(value);
- }
- return nv;
- }
-
- public static NameValueUnit createStringNVU(String valName, String value) {
- NameValueUnit nvu = new NameValueUnit();
- nvu.valName = valName;
- nvu.value = new TS_Value();
- nvu.unit = "";
- nvu.value.u = new TS_Union();
- if (value == null || value.length() < 1) {
- nvu.value.flag = 0;
- nvu.value.u.stringVal("");
- } else {
- nvu.value.flag = 15;
- nvu.value.u.stringVal(value);
- }
- return nvu;
- }
-
- public static NameValue createShortNV(String valName, short value) {
- TS_Union union = new TS_Union();
- union.shortVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createShortNVU(String valName, short value) {
- TS_Union union = new TS_Union();
- union.shortVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValueUnit createShortNVU(String valName, short value, String unit) {
- TS_Union union = new TS_Union();
- union.shortVal(value);
- return createNVU(valName, union, unit);
- }
-
- public static NameValue createFloatNV(String valName, float value) {
- TS_Union union = new TS_Union();
- union.floatVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createFloatNVU(String valName, float value) {
- TS_Union union = new TS_Union();
- union.floatVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValueUnit createFloatNVU(String valName, float value, String unit) {
- TS_Union union = new TS_Union();
- union.floatVal(value);
- return createNVU(valName, union, unit);
- }
-
- public static NameValue createBooleanNV(String valName, boolean value) {
- TS_Union union = new TS_Union();
- union.booleanVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createBooleanNVU(String valName, boolean value) {
- TS_Union union = new TS_Union();
- union.booleanVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createByteNV(String valName, byte value) {
- TS_Union union = new TS_Union();
- union.byteVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createByteNVU(String valName, byte value) {
- TS_Union union = new TS_Union();
- union.byteVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createBytestrNV(String valName, byte value[]) {
- TS_Union union = new TS_Union();
- union.bytestrVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createBytestrNVU(String valName, byte value[]) {
- TS_Union union = new TS_Union();
- union.bytestrVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createDoubleNV(String valName, double value) {
- TS_Union union = new TS_Union();
- union.doubleVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createDoubleNVU(String valName, Double value) {
- NameValueUnit nvu = new NameValueUnit();
- nvu.valName = valName;
- nvu.value = new TS_Value();
- nvu.unit = "";
- nvu.value.u = new TS_Union();
- if (value == null) {
- nvu.value.flag = 0;
- nvu.value.u.doubleVal(0);
- } else {
- nvu.value.flag = 15;
- nvu.value.u.doubleVal(value);
- }
- return nvu;
- }
-
- public static NameValue createDComplexNV(String valName, T_DCOMPLEX value) {
- TS_Union union = new TS_Union();
- union.dcomplexVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createDComplexNVU(String valName, T_DCOMPLEX value) {
- TS_Union union = new TS_Union();
- union.dcomplexVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValueUnit createDoubleNVU(String valName, double value, String unit) {
- TS_Union union = new TS_Union();
- union.doubleVal(value);
- return createNVU(valName, union, unit);
- }
-
- public static NameValue createLongNV(String valName, int value) {
- TS_Union union = new TS_Union();
- union.longVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createLongNVU(String valName, int value) {
- TS_Union union = new TS_Union();
- union.longVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValueUnit createLongNVU(String valName, int value, String unit) {
- TS_Union union = new TS_Union();
- union.longVal(value);
- return createNVU(valName, union, unit);
- }
-
- public static NameValue createLongLongNV(String valName, T_LONGLONG value) {
- TS_Union union = new TS_Union();
- union.longlongVal(value);
- return createNV(valName, union);
- }
-
- public static NameValue createLongLongNV(String valName, long value) {
- return createLongLongNV(valName, asODSLongLong(value));
- }
-
- public static NameValueUnit createLongLongNVU(String valName, long value) {
- TS_Union union = new TS_Union();
- union.longlongVal(asODSLongLong(value));
- return createNVU(valName, union);
- }
-
- public static NameValueUnit createLongLongNVU(String valName, long value, String unit) {
- TS_Union union = new TS_Union();
- union.longlongVal(asODSLongLong(value));
- return createNVU(valName, union, unit);
- }
-
- public static NameValue createDateNV(String valName, String value) {
- NameValue nv = new NameValue();
- nv.valName = valName;
- nv.value = new TS_Value();
- nv.value.u = new TS_Union();
- if (value == null || value.length() < 1) {
- nv.value.flag = 0;
- nv.value.u.dateVal("");
- } else {
- nv.value.flag = 15;
- nv.value.u.dateVal(value);
- }
- return nv;
- }
-
- public static NameValue createDateNV(String valName, Date value) {
- return createDateNV(valName, asODSDate(value));
- }
-
- public static NameValueUnit createDateNVU(String valName, String value) {
- NameValueUnit nvu = new NameValueUnit();
- nvu.valName = valName;
- nvu.value = new TS_Value();
- nvu.unit = "";
- nvu.value.u = new TS_Union();
- if (value == null || value.length() < 1) {
- nvu.value.flag = 0;
- nvu.value.u.dateVal("");
- } else {
- nvu.value.flag = 15;
- nvu.value.u.dateVal(value);
- }
- return nvu;
- }
-
- public static NameValueUnit createDateNVU(String valName, Date value) {
- return createDateNVU(valName, asODSDate(value));
- }
-
- public static NameValue createEnumNV(String valName, int value) {
- TS_Union union = new TS_Union();
- union.enumVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createEnumNVU(String valName, int value) {
- TS_Union union = new TS_Union();
- union.enumVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createExtRefNV(String valName, T_ExternalReference value) {
- TS_Union union = new TS_Union();
- union.extRefVal(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createExtRefNVU(String valName, T_ExternalReference value) {
- TS_Union union = new TS_Union();
- union.extRefVal(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createStringSeqNV(String valName, String values[]) {
- TS_Union union = new TS_Union();
- union.stringSeq(values);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createStringSeqNVU(String valName, String values[]) {
- TS_Union union = new TS_Union();
- union.stringSeq(values);
- return createNVU(valName, union);
- }
-
- public static NameValue createShortSeqNV(String valName, short values[]) {
- TS_Union union = new TS_Union();
- union.shortSeq(values);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createShortSeqNVU(String attrName, short values[]) {
- TS_Union union = new TS_Union();
- union.shortSeq(values);
- return createNVU(attrName, union);
- }
-
- public static NameValue createFloatSeqNV(String attrName, float values[]) {
- TS_Union union = new TS_Union();
- union.floatSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValueUnit createFloatSeqNVU(String attrName, float values[]) {
- TS_Union union = new TS_Union();
- union.floatSeq(values);
- return createNVU(attrName, union);
- }
-
- public static NameValue createBooleanSeqNV(String attrName, boolean values[]) {
- TS_Union union = new TS_Union();
- union.booleanSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValueUnit createBooleanSeqNVU(String attrName, boolean values[]) {
- TS_Union union = new TS_Union();
- union.booleanSeq(values);
- return createNVU(attrName, union);
- }
-
- public static NameValue createByteSeqNV(String attrName, byte values[]) {
- TS_Union union = new TS_Union();
- union.byteSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValueUnit createByteSeqNVU(String attrName, byte values[]) {
- TS_Union union = new TS_Union();
- union.byteSeq(values);
- return createNVU(attrName, union);
- }
-
- public static NameValue createBytestrSeqNV(String valName, byte value[][]) {
- TS_Union union = new TS_Union();
- union.bytestrSeq(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createBytestrSeqNVU(String valName, byte value[][]) {
- TS_Union union = new TS_Union();
- union.bytestrSeq(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createDComplexSeqNV(String valName, T_DCOMPLEX value[]) {
- TS_Union union = new TS_Union();
- union.dcomplexSeq(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createDComplexSeqNVU(String valName, T_DCOMPLEX value[]) {
- TS_Union union = new TS_Union();
- union.dcomplexSeq(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createDoubleSeqNV(String attrName, double values[]) {
- TS_Union union = new TS_Union();
- union.doubleSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValueUnit createDoubleSeqNVU(String attrName, double values[]) {
- TS_Union union = new TS_Union();
- union.doubleSeq(values);
- return createNVU(attrName, union);
- }
-
- public static NameValue createEnumSeqNV(String valName, int value[]) {
- TS_Union union = new TS_Union();
- union.enumSeq(value);
- return createNV(valName, union);
- }
-
- public static NameValueUnit createEnumSeqNVU(String valName, int value[]) {
- TS_Union union = new TS_Union();
- union.enumSeq(value);
- return createNVU(valName, union);
- }
-
- public static NameValue createLongSeqNV(String attrName, int values[]) {
- TS_Union union = new TS_Union();
- union.longSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValueUnit createLongSeqNVU(String attrName, int values[]) {
- TS_Union union = new TS_Union();
- union.longSeq(values);
- return createNVU(attrName, union);
- }
-
- public static NameValue createLongLongSeqNV(String attrName, T_LONGLONG values[]) {
- TS_Union union = new TS_Union();
- union.longlongSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValue createLongLongSeqNV(String attrName, long values[]) {
- TS_Union union = new TS_Union();
- union.longlongSeq(asODSLongLong(values));
- return createNV(attrName, union);
- }
-
- public static NameValueUnit createLongLongSeqNVU(String attrName, long values[]) {
- TS_Union union = new TS_Union();
- union.longlongSeq(asODSLongLong(values));
- return createNVU(attrName, union);
- }
-
- public static NameValue createDateSeqNV(String attrName, String values[]) {
- TS_Union union = new TS_Union();
- union.dateSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValue createDateSeqNV(String attrName, Date values[]) {
- String[] valuesstr = new String[values.length];
- for (int i = 0; i < values.length; i++) {
- valuesstr[i] = ODSHelper.asODSDate(values[i]);
- }
- return createDateSeqNV(attrName, valuesstr);
- }
-
- public static NameValueUnit createDateSeqNVU(String attrName, String values[]) {
- TS_Union union = new TS_Union();
- union.dateSeq(values);
- return createNVU(attrName, union);
- }
-
- public static NameValue createExtRefSeqNV(String attrName, T_ExternalReference values[]) {
- TS_Union union = new TS_Union();
- union.extRefSeq(values);
- return createNV(attrName, union);
- }
-
- public static NameValueUnit createExtRefSeqNVU(String attrName, T_ExternalReference values[]) {
- TS_Union union = new TS_Union();
- union.extRefSeq(values);
- return createNVU(attrName, union);
- }
-
- public static boolean isNullVal(TS_Value value) {
- if (value.flag != 15) {
- return true;
- }
- return false;
- }
-
- public static boolean isNullVal(NameValueUnit nvu) {
- if (nvu.value.flag != 15) {
- return true;
- }
- return false;
- }
-
- public static long getLongLongVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return 0;
- } else {
- return asJLong(nvu.value.u.longlongVal());
- }
- }
-
- public static int getLongVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return 0;
- } else {
- return nvu.value.u.longVal();
- }
- }
-
- public static double getDoubleVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return 0d;
- } else {
- return nvu.value.u.doubleVal();
- }
- }
-
- public static short getShortVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return (short) 0;
- } else {
- return nvu.value.u.shortVal();
- }
- }
-
- public static byte getByteVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return (byte) 0;
- } else {
- return nvu.value.u.byteVal();
- }
- }
-
- public static float getFloatVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return 0f;
- } else {
- return nvu.value.u.floatVal();
- }
- }
-
- public static String getStringVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return "";
- } else {
- return nvu.value.u.stringVal();
- }
- }
-
- public static int getEnumVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return 0;
- } else {
- return nvu.value.u.enumVal();
- }
- }
-
- public static String getDateVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return "";
- } else {
- return nvu.value.u.dateVal();
- }
- }
-
- public static boolean getBooleanVal(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return false;
- } else {
- return nvu.value.u.booleanVal();
- }
- }
-
- public static String[] getStringSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new String[0];
- } else {
- return nvu.value.u.stringSeq();
- }
- }
-
- public static short[] getShortSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new short[0];
- } else {
- return nvu.value.u.shortSeq();
- }
- }
-
- public static float[] getFloatSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new float[0];
- } else {
- return nvu.value.u.floatSeq();
- }
- }
-
- public static boolean[] getBooleanSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new boolean[0];
- } else {
- return nvu.value.u.booleanSeq();
- }
- }
-
- public static byte[] getByteSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new byte[0];
- } else {
- return nvu.value.u.byteSeq();
- }
- }
-
- public static int[] getLongSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new int[0];
- } else {
- return nvu.value.u.longSeq();
- }
- }
-
- public static double[] getDoubleSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new double[0];
- } else {
- return nvu.value.u.doubleSeq();
- }
- }
-
- public static long[] getLongLongSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new long[0];
- } else {
- return asJLong(nvu.value.u.longlongSeq());
- }
- }
-
- public static String[] getDateSeq(NameValueUnit nvu) {
- if (isNullVal(nvu)) {
- return new String[0];
- } else {
- return nvu.value.u.stringSeq();
- }
- }
-
- public static void setBit(byte[] data, int pos, boolean val) {
- int posByte = pos / 8;
- int posBit = pos % 8;
- byte oldByte = data[posByte];
- if (val) {
- data[posByte] = (byte) (oldByte | 1 << 7 - posBit);
- } else {
- data[posByte] = (byte) (oldByte | 0 << 7 - posBit);
- }
- }
-
-}
+
+
+package org.eclipse.mdm.openatfx.mdf.util;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.asam.ods.NameValue;
+import org.asam.ods.NameValueUnit;
+import org.asam.ods.TS_Union;
+import org.asam.ods.TS_Value;
+import org.asam.ods.T_DCOMPLEX;
+import org.asam.ods.T_ExternalReference;
+import org.asam.ods.T_LONGLONG;
+
+/**
+ * Helper class with ODS specific functions.
+ *
+ * @author Christian Rechner
+ */
+public abstract class ODSHelper {
+
+ // prepare dateformats to avoid instantiation a single object every time
+ // parsing a date.
+ private static Map<Integer, DateFormat> ODS_DATEFORMATS = new HashMap<Integer, DateFormat>();
+ static {
+ ODS_DATEFORMATS.put(4, new SimpleDateFormat("yyyy"));
+ ODS_DATEFORMATS.put(6, new SimpleDateFormat("yyyyMM"));
+ ODS_DATEFORMATS.put(8, new SimpleDateFormat("yyyyMMdd"));
+ ODS_DATEFORMATS.put(10, new SimpleDateFormat("yyyyMMddHH"));
+ ODS_DATEFORMATS.put(12, new SimpleDateFormat("yyyyMMddHHmm"));
+ ODS_DATEFORMATS.put(14, new SimpleDateFormat("yyyyMMddHHmmss"));
+ ODS_DATEFORMATS.put(17, new SimpleDateFormat("yyyyMMddHHmmssSSS"));
+ }
+
+ /**
+ * Return an ODS date from a <code>java.util.Date</code>.
+ *
+ * @param date
+ * the <code>java.util.Date</code> to convert
+ * @return the date in ODS date-format (YYYYMMDDhhmmss)
+ */
+ public static synchronized String asODSDate(Date date) {
+ if (date == null) {
+ return "";
+ }
+ return ODS_DATEFORMATS.get(14).format(date);
+ }
+
+ /**
+ * Returns the java date from an ODS date.
+ *
+ * @param odsDate
+ * the ODS date string
+ * @return the java <code>java.util.Date</code> object, null if empty date
+ * @throws IllegalArgumentException
+ * unable to parse
+ */
+ public static synchronized Date asJDate(String odsDate) {
+ try {
+ if (odsDate == null || odsDate.length() < 1) {
+ return null;
+ }
+ DateFormat format = ODS_DATEFORMATS.get(odsDate.length());
+ if (format == null) {
+ throw new IllegalArgumentException("Invalid ODS date: " + odsDate);
+ }
+ return format.parse(odsDate);
+ } catch (ParseException e) {
+ throw new IllegalArgumentException("Invalid ODS date: " + odsDate);
+ }
+ }
+
+ /**
+ * Returns a Java long from ODS T_LONGLONG.
+ *
+ * @param ll
+ * ODS T_LONGLONG value
+ * @return Java long with the same value as ll
+ */
+ public static long asJLong(T_LONGLONG ll) {
+ long tmp;
+ if (ll.low >= 0) {
+ tmp = ll.high * 0x100000000L + ll.low;
+ } else {
+ tmp = (ll.high + 1) * 0x100000000L + ll.low;
+ }
+ return tmp;
+ }
+
+ /**
+ * Returns an array of Java long from ODS T_LONGLONG.
+ *
+ * @param ll
+ * array of ODS T_LONGLONG values
+ * @return array of Java long values
+ */
+ public static long[] asJLong(T_LONGLONG[] ll) {
+ long[] ar = new long[ll.length];
+ for (int i = 0; i < ll.length; i++) {
+ ar[i] = asJLong(ll[i]);
+ }
+ return ar;
+ }
+
+ /**
+ * Return ODS T_LONGLONG from Java long.
+ *
+ * @param v
+ * Java long value
+ * @return ODS T_LONGLONG with the same value as v
+ */
+ public static T_LONGLONG asODSLongLong(long v) {
+ return new T_LONGLONG((int) (v >> 32 & 0xffffffffL), (int) (v & 0xffffffffL));
+ }
+
+ /**
+ * Returns an array of ODS T_LONGLONG from Java longs.
+ *
+ * @param v
+ * array of Java long values
+ * @return array of ODS T_LONGLONG values
+ */
+ public static T_LONGLONG[] asODSLongLong(long[] v) {
+ T_LONGLONG[] ar = new T_LONGLONG[v.length];
+ for (int i = 0; i < v.length; i++) {
+ ar[i] = asODSLongLong(v[i]);
+ }
+ return ar;
+ }
+
+ public static String getCurrentODSDate() {
+ return asODSDate(new Date());
+ }
+
+ private static NameValue createNV(String valName, TS_Union union) {
+ NameValue nv = new NameValue();
+ nv.valName = valName;
+ nv.value = new TS_Value();
+ nv.value.flag = 15;
+ nv.value.u = union;
+ return nv;
+ }
+
+ private static NameValueUnit createNVU(String attrName, TS_Union union) {
+ NameValueUnit nvu = new NameValueUnit();
+ nvu.valName = attrName;
+ nvu.value = new TS_Value();
+ nvu.unit = "";
+ nvu.value.flag = 15;
+ nvu.value.u = union;
+ return nvu;
+ }
+
+ private static NameValueUnit createNVU(String attrName, TS_Union union, String unit) {
+ NameValueUnit nvu = new NameValueUnit();
+ nvu.valName = attrName;
+ nvu.value = new TS_Value();
+ nvu.value.u = new TS_Union();
+ nvu.unit = unit;
+ nvu.value.flag = 15;
+ nvu.value.u = union;
+ return nvu;
+ }
+
+ public static NameValueUnit createCurrentDateNVU(String attrName) {
+ TS_Union union = new TS_Union();
+ union.dateVal(getCurrentODSDate());
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createStringNV(String valName, String value) {
+ NameValue nv = new NameValue();
+ nv.valName = valName;
+ nv.value = new TS_Value();
+ nv.value.u = new TS_Union();
+ if (value == null) {
+ nv.value.flag = 0;
+ nv.value.u.stringVal("");
+ } else {
+ nv.value.flag = 15;
+ nv.value.u.stringVal(value);
+ }
+ return nv;
+ }
+
+ public static NameValueUnit createStringNVU(String valName, String value) {
+ NameValueUnit nvu = new NameValueUnit();
+ nvu.valName = valName;
+ nvu.value = new TS_Value();
+ nvu.unit = "";
+ nvu.value.u = new TS_Union();
+ if (value == null || value.length() < 1) {
+ nvu.value.flag = 0;
+ nvu.value.u.stringVal("");
+ } else {
+ nvu.value.flag = 15;
+ nvu.value.u.stringVal(value);
+ }
+ return nvu;
+ }
+
+ public static NameValue createShortNV(String valName, short value) {
+ TS_Union union = new TS_Union();
+ union.shortVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createShortNVU(String valName, short value) {
+ TS_Union union = new TS_Union();
+ union.shortVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValueUnit createShortNVU(String valName, short value, String unit) {
+ TS_Union union = new TS_Union();
+ union.shortVal(value);
+ return createNVU(valName, union, unit);
+ }
+
+ public static NameValue createFloatNV(String valName, float value) {
+ TS_Union union = new TS_Union();
+ union.floatVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createFloatNVU(String valName, float value) {
+ TS_Union union = new TS_Union();
+ union.floatVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValueUnit createFloatNVU(String valName, float value, String unit) {
+ TS_Union union = new TS_Union();
+ union.floatVal(value);
+ return createNVU(valName, union, unit);
+ }
+
+ public static NameValue createBooleanNV(String valName, boolean value) {
+ TS_Union union = new TS_Union();
+ union.booleanVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createBooleanNVU(String valName, boolean value) {
+ TS_Union union = new TS_Union();
+ union.booleanVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createByteNV(String valName, byte value) {
+ TS_Union union = new TS_Union();
+ union.byteVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createByteNVU(String valName, byte value) {
+ TS_Union union = new TS_Union();
+ union.byteVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createBytestrNV(String valName, byte value[]) {
+ TS_Union union = new TS_Union();
+ union.bytestrVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createBytestrNVU(String valName, byte value[]) {
+ TS_Union union = new TS_Union();
+ union.bytestrVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createDoubleNV(String valName, double value) {
+ TS_Union union = new TS_Union();
+ union.doubleVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createDoubleNVU(String valName, Double value) {
+ NameValueUnit nvu = new NameValueUnit();
+ nvu.valName = valName;
+ nvu.value = new TS_Value();
+ nvu.unit = "";
+ nvu.value.u = new TS_Union();
+ if (value == null) {
+ nvu.value.flag = 0;
+ nvu.value.u.doubleVal(0);
+ } else {
+ nvu.value.flag = 15;
+ nvu.value.u.doubleVal(value);
+ }
+ return nvu;
+ }
+
+ public static NameValue createDComplexNV(String valName, T_DCOMPLEX value) {
+ TS_Union union = new TS_Union();
+ union.dcomplexVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createDComplexNVU(String valName, T_DCOMPLEX value) {
+ TS_Union union = new TS_Union();
+ union.dcomplexVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValueUnit createDoubleNVU(String valName, double value, String unit) {
+ TS_Union union = new TS_Union();
+ union.doubleVal(value);
+ return createNVU(valName, union, unit);
+ }
+
+ public static NameValue createLongNV(String valName, int value) {
+ TS_Union union = new TS_Union();
+ union.longVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createLongNVU(String valName, int value) {
+ TS_Union union = new TS_Union();
+ union.longVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValueUnit createLongNVU(String valName, int value, String unit) {
+ TS_Union union = new TS_Union();
+ union.longVal(value);
+ return createNVU(valName, union, unit);
+ }
+
+ public static NameValue createLongLongNV(String valName, T_LONGLONG value) {
+ TS_Union union = new TS_Union();
+ union.longlongVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValue createLongLongNV(String valName, long value) {
+ return createLongLongNV(valName, asODSLongLong(value));
+ }
+
+ public static NameValueUnit createLongLongNVU(String valName, long value) {
+ TS_Union union = new TS_Union();
+ union.longlongVal(asODSLongLong(value));
+ return createNVU(valName, union);
+ }
+
+ public static NameValueUnit createLongLongNVU(String valName, long value, String unit) {
+ TS_Union union = new TS_Union();
+ union.longlongVal(asODSLongLong(value));
+ return createNVU(valName, union, unit);
+ }
+
+ public static NameValue createDateNV(String valName, String value) {
+ NameValue nv = new NameValue();
+ nv.valName = valName;
+ nv.value = new TS_Value();
+ nv.value.u = new TS_Union();
+ if (value == null || value.length() < 1) {
+ nv.value.flag = 0;
+ nv.value.u.dateVal("");
+ } else {
+ nv.value.flag = 15;
+ nv.value.u.dateVal(value);
+ }
+ return nv;
+ }
+
+ public static NameValue createDateNV(String valName, Date value) {
+ return createDateNV(valName, asODSDate(value));
+ }
+
+ public static NameValueUnit createDateNVU(String valName, String value) {
+ NameValueUnit nvu = new NameValueUnit();
+ nvu.valName = valName;
+ nvu.value = new TS_Value();
+ nvu.unit = "";
+ nvu.value.u = new TS_Union();
+ if (value == null || value.length() < 1) {
+ nvu.value.flag = 0;
+ nvu.value.u.dateVal("");
+ } else {
+ nvu.value.flag = 15;
+ nvu.value.u.dateVal(value);
+ }
+ return nvu;
+ }
+
+ public static NameValueUnit createDateNVU(String valName, Date value) {
+ return createDateNVU(valName, asODSDate(value));
+ }
+
+ public static NameValue createEnumNV(String valName, int value) {
+ TS_Union union = new TS_Union();
+ union.enumVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createEnumNVU(String valName, int value) {
+ TS_Union union = new TS_Union();
+ union.enumVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createExtRefNV(String valName, T_ExternalReference value) {
+ TS_Union union = new TS_Union();
+ union.extRefVal(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createExtRefNVU(String valName, T_ExternalReference value) {
+ TS_Union union = new TS_Union();
+ union.extRefVal(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createStringSeqNV(String valName, String values[]) {
+ TS_Union union = new TS_Union();
+ union.stringSeq(values);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createStringSeqNVU(String valName, String values[]) {
+ TS_Union union = new TS_Union();
+ union.stringSeq(values);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createShortSeqNV(String valName, short values[]) {
+ TS_Union union = new TS_Union();
+ union.shortSeq(values);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createShortSeqNVU(String attrName, short values[]) {
+ TS_Union union = new TS_Union();
+ union.shortSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createFloatSeqNV(String attrName, float values[]) {
+ TS_Union union = new TS_Union();
+ union.floatSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValueUnit createFloatSeqNVU(String attrName, float values[]) {
+ TS_Union union = new TS_Union();
+ union.floatSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createBooleanSeqNV(String attrName, boolean values[]) {
+ TS_Union union = new TS_Union();
+ union.booleanSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValueUnit createBooleanSeqNVU(String attrName, boolean values[]) {
+ TS_Union union = new TS_Union();
+ union.booleanSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createByteSeqNV(String attrName, byte values[]) {
+ TS_Union union = new TS_Union();
+ union.byteSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValueUnit createByteSeqNVU(String attrName, byte values[]) {
+ TS_Union union = new TS_Union();
+ union.byteSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createBytestrSeqNV(String valName, byte value[][]) {
+ TS_Union union = new TS_Union();
+ union.bytestrSeq(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createBytestrSeqNVU(String valName, byte value[][]) {
+ TS_Union union = new TS_Union();
+ union.bytestrSeq(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createDComplexSeqNV(String valName, T_DCOMPLEX value[]) {
+ TS_Union union = new TS_Union();
+ union.dcomplexSeq(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createDComplexSeqNVU(String valName, T_DCOMPLEX value[]) {
+ TS_Union union = new TS_Union();
+ union.dcomplexSeq(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createDoubleSeqNV(String attrName, double values[]) {
+ TS_Union union = new TS_Union();
+ union.doubleSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValueUnit createDoubleSeqNVU(String attrName, double values[]) {
+ TS_Union union = new TS_Union();
+ union.doubleSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createEnumSeqNV(String valName, int value[]) {
+ TS_Union union = new TS_Union();
+ union.enumSeq(value);
+ return createNV(valName, union);
+ }
+
+ public static NameValueUnit createEnumSeqNVU(String valName, int value[]) {
+ TS_Union union = new TS_Union();
+ union.enumSeq(value);
+ return createNVU(valName, union);
+ }
+
+ public static NameValue createLongSeqNV(String attrName, int values[]) {
+ TS_Union union = new TS_Union();
+ union.longSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValueUnit createLongSeqNVU(String attrName, int values[]) {
+ TS_Union union = new TS_Union();
+ union.longSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createLongLongSeqNV(String attrName, T_LONGLONG values[]) {
+ TS_Union union = new TS_Union();
+ union.longlongSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValue createLongLongSeqNV(String attrName, long values[]) {
+ TS_Union union = new TS_Union();
+ union.longlongSeq(asODSLongLong(values));
+ return createNV(attrName, union);
+ }
+
+ public static NameValueUnit createLongLongSeqNVU(String attrName, long values[]) {
+ TS_Union union = new TS_Union();
+ union.longlongSeq(asODSLongLong(values));
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createDateSeqNV(String attrName, String values[]) {
+ TS_Union union = new TS_Union();
+ union.dateSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValue createDateSeqNV(String attrName, Date values[]) {
+ String[] valuesstr = new String[values.length];
+ for (int i = 0; i < values.length; i++) {
+ valuesstr[i] = ODSHelper.asODSDate(values[i]);
+ }
+ return createDateSeqNV(attrName, valuesstr);
+ }
+
+ public static NameValueUnit createDateSeqNVU(String attrName, String values[]) {
+ TS_Union union = new TS_Union();
+ union.dateSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static NameValue createExtRefSeqNV(String attrName, T_ExternalReference values[]) {
+ TS_Union union = new TS_Union();
+ union.extRefSeq(values);
+ return createNV(attrName, union);
+ }
+
+ public static NameValueUnit createExtRefSeqNVU(String attrName, T_ExternalReference values[]) {
+ TS_Union union = new TS_Union();
+ union.extRefSeq(values);
+ return createNVU(attrName, union);
+ }
+
+ public static boolean isNullVal(TS_Value value) {
+ if (value.flag != 15) {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isNullVal(NameValueUnit nvu) {
+ if (nvu.value.flag != 15) {
+ return true;
+ }
+ return false;
+ }
+
+ public static long getLongLongVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return 0;
+ } else {
+ return asJLong(nvu.value.u.longlongVal());
+ }
+ }
+
+ public static int getLongVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return 0;
+ } else {
+ return nvu.value.u.longVal();
+ }
+ }
+
+ public static double getDoubleVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return 0d;
+ } else {
+ return nvu.value.u.doubleVal();
+ }
+ }
+
+ public static short getShortVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return (short) 0;
+ } else {
+ return nvu.value.u.shortVal();
+ }
+ }
+
+ public static byte getByteVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return (byte) 0;
+ } else {
+ return nvu.value.u.byteVal();
+ }
+ }
+
+ public static float getFloatVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return 0f;
+ } else {
+ return nvu.value.u.floatVal();
+ }
+ }
+
+ public static String getStringVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return "";
+ } else {
+ return nvu.value.u.stringVal();
+ }
+ }
+
+ public static int getEnumVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return 0;
+ } else {
+ return nvu.value.u.enumVal();
+ }
+ }
+
+ public static String getDateVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return "";
+ } else {
+ return nvu.value.u.dateVal();
+ }
+ }
+
+ public static boolean getBooleanVal(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return false;
+ } else {
+ return nvu.value.u.booleanVal();
+ }
+ }
+
+ public static String[] getStringSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new String[0];
+ } else {
+ return nvu.value.u.stringSeq();
+ }
+ }
+
+ public static short[] getShortSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new short[0];
+ } else {
+ return nvu.value.u.shortSeq();
+ }
+ }
+
+ public static float[] getFloatSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new float[0];
+ } else {
+ return nvu.value.u.floatSeq();
+ }
+ }
+
+ public static boolean[] getBooleanSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new boolean[0];
+ } else {
+ return nvu.value.u.booleanSeq();
+ }
+ }
+
+ public static byte[] getByteSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new byte[0];
+ } else {
+ return nvu.value.u.byteSeq();
+ }
+ }
+
+ public static int[] getLongSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new int[0];
+ } else {
+ return nvu.value.u.longSeq();
+ }
+ }
+
+ public static double[] getDoubleSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new double[0];
+ } else {
+ return nvu.value.u.doubleSeq();
+ }
+ }
+
+ public static long[] getLongLongSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new long[0];
+ } else {
+ return asJLong(nvu.value.u.longlongSeq());
+ }
+ }
+
+ public static String[] getDateSeq(NameValueUnit nvu) {
+ if (isNullVal(nvu)) {
+ return new String[0];
+ } else {
+ return nvu.value.u.stringSeq();
+ }
+ }
+
+ public static void setBit(byte[] data, int pos, boolean val) {
+ int posByte = pos / 8;
+ int posBit = pos % 8;
+ byte oldByte = data[posByte];
+ if (val) {
+ data[posByte] = (byte) (oldByte | 1 << 7 - posBit);
+ } else {
+ data[posByte] = (byte) (oldByte | 0 << 7 - posBit);
+ }
+ }
+
+}
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSInsertStatement.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSInsertStatement.java
index 1316eb2..c097f86 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSInsertStatement.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSInsertStatement.java
@@ -598,7 +598,8 @@
}
// do not insert if attribute is "id"
- if (cache.applAttrExists(aeName, attr) && cache.getApplAttr(aeName, attr).baName.equals("id")) {
+ if (cache.applAttrExists(aeName, attr) && cache.getApplAttr(aeName, attr).baName != null
+ && cache.getApplAttr(aeName, attr).baName.equals("id")) {
continue;
}
diff --git a/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSModelCache.java b/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSModelCache.java
index 5924fb8..2757db8 100644
--- a/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSModelCache.java
+++ b/src/main/java/org/eclipse/mdm/openatfx/mdf/util/ODSModelCache.java
@@ -32,10 +32,12 @@
import org.asam.ods.ApplicationElement;
import org.asam.ods.ApplicationRelation;
import org.asam.ods.ApplicationStructure;
-import org.asam.ods.ApplicationStructureValue;
+import org.asam.ods.ApplicationStructureValue;
+import org.asam.ods.BaseAttribute;
import org.asam.ods.BaseElement;
import org.asam.ods.BaseRelation;
-import org.asam.ods.BaseStructure;
+import org.asam.ods.BaseStructure;
+import org.asam.ods.DataType;
import org.asam.ods.ElemId;
import org.asam.ods.EnumerationAttributeStructure;
import org.asam.ods.EnumerationDefinition;
@@ -53,6 +55,10 @@
* @author Christian Rechner
*/
public class ODSModelCache {
+
+ public static final String ATTR_NAME_MEAQU_RANK = "rank";
+ public static final String ATTR_NAME_MEAQU_DIMENSION = "dimension";
+ public static final String ATTR_NAME_MEAQU_COL_ORIENTED_TENSOR = "columnOriented";
private static final Log LOG = LogFactory.getLog(ODSModelCache.class);
@@ -122,9 +128,58 @@
applicationElemCache = new HashMap<String, ApplicationElement>();
applicationAttrCache = new HashMap<String, ApplicationAttribute[]>();
applicationRelCache = new HashMap<ApplicationRelKey, ApplicationRelation>();
- enumDefCache = new HashMap<String, EnumerationDefinition>();
+ enumDefCache = new HashMap<String, EnumerationDefinition>();
+
+ try
+ {
+ extendSourceApplicationStructure(aoSession);
+ }
+ catch (AoException e)
+ {
+ throw new RuntimeException("Error occurred trying to extend mdf datamodel with required additions: " + e.reason);
+ }
+
this.aoSession = aoSession;
- }
+ }
+
+ /**
+ * <p>
+ * Adds attributes to model needed additionally to transport information on
+ * specific mdf features to the ODS target. So far these are:
+ * </p>
+ * <p>
+ * For array composition:
+ * <ul>
+ * <li>MeaQuantity - rank attribute: for the number of value dimensions in the
+ * values tensor for this channel</li>
+ * <li>MeaQuantity - dimension attribute: for the number of values in each
+ * dimension of the values tensor for this channel</li>
+ * <li>MeaQuantity - columnOriented attribute: to specify in which way the
+ * tensor has to be interpreted when calculating the actual values</li>
+ * </ul>
+ * </p>
+ * @throws AoException
+ */
+ private final void extendSourceApplicationStructure(AoSession aoSession) throws AoException
+ {
+ ApplicationStructure as = aoSession.getApplicationStructure();
+
+ // Additional MeasurementQuantity attributes
+ ApplicationElement meaQuantityAe = as.getElementsByBaseType("aomeasurementquantity")[0];
+
+ // to handle array composition for channels
+ ApplicationAttribute rankAttr = meaQuantityAe.createAttribute();
+ BaseAttribute rankBaseAttr = meaQuantityAe.getBaseElement().getAttributes("rank")[0];
+ rankAttr.setBaseAttribute(rankBaseAttr);
+ rankAttr.setName(ATTR_NAME_MEAQU_RANK);
+ ApplicationAttribute dimensionAttr = meaQuantityAe.createAttribute();
+ BaseAttribute dimensionBaseAttr = meaQuantityAe.getBaseElement().getAttributes("dimension")[0];
+ dimensionAttr.setBaseAttribute(dimensionBaseAttr);
+ dimensionAttr.setName(ATTR_NAME_MEAQU_DIMENSION);
+ ApplicationAttribute columnOrientedAttr = meaQuantityAe.createAttribute();
+ columnOrientedAttr.setName(ATTR_NAME_MEAQU_COL_ORIENTED_TENSOR);
+ columnOrientedAttr.setDataType(DataType.DT_BOOLEAN);
+ }
/**
* Returns a Java long from ODS T_LONGLONG.
@@ -537,7 +592,7 @@
public final ApplElem[] getApplElemsByBaseName(String beName) throws AoException {
List<ApplElem> list = new LinkedList<ApplElem>();
for (ApplElem applElem : getApplElems()) {
- if (applElem.beName.equals(beName)) {
+ if (applElem.beName.equalsIgnoreCase(beName)) {
list.add(applElem);
}
}