NIFI-10722 - Add handling of TBCD-STRING in nifi-asn1-services

This closes #6611

Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
Tamas Palfy 2022-11-02 16:59:47 +01:00 committed by exceptionfactory
parent 4083e07447
commit 56af75f5bd
No known key found for this signature in database
GPG Key ID: 29B6A52D2AAE8DBA
7 changed files with 175 additions and 0 deletions

View File

@ -92,6 +92,7 @@
<argument>${basedir}/src/test/resources/simple_types.asn</argument>
<argument>${basedir}/src/test/resources/complex_types.asn</argument>
<argument>${basedir}/src/test/resources/example.asn</argument>
<argument>${basedir}/src/test/resources/tbcd_string.asn</argument>
<argument>-o</argument>
<argument>${basedir}/target/generated-test-sources</argument>
</arguments>
@ -128,8 +129,10 @@
<exclude>src/test/resources/example.asn</exclude>
<exclude>src/test/resources/simple_types.asn</exclude>
<exclude>src/test/resources/complex_types.asn</exclude>
<exclude>src/test/resources/tbcd_string.asn</exclude>
<exclude>src/test/resources/examples/basic-types.dat</exclude>
<exclude>src/test/resources/examples/composite.dat</exclude>
<exclude>src/test/resources/examples/tbcd-string.dat</exclude>
</excludes>
</configuration>
</plugin>

View File

@ -29,6 +29,7 @@ import org.apache.nifi.jasn1.convert.converters.BerOctetStringConverter;
import org.apache.nifi.jasn1.convert.converters.BerRealConverter;
import org.apache.nifi.jasn1.convert.converters.BerRecordConverter;
import org.apache.nifi.jasn1.convert.converters.BerStringConverter;
import org.apache.nifi.jasn1.convert.converters.TbcdStringConverter;
import org.apache.nifi.jasn1.convert.converters.BerTimeOfDayConverter;
import org.apache.nifi.serialization.record.DataType;
import org.apache.nifi.serialization.record.RecordSchema;
@ -50,6 +51,7 @@ public class JASN1ConverterImpl implements JASN1Converter {
new BerDateTimeConverter(),
new BerRealConverter(),
new BerStringConverter(),
new TbcdStringConverter(),
new BerOctetStringConverter(),
new BerArrayConverter(),
new BerRecordConverter(schemaProvider)

View File

@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.jasn1.convert.converters;
import com.beanit.asn1bean.ber.types.BerOctetString;
import com.beanit.asn1bean.ber.types.BerType;
import org.apache.nifi.jasn1.convert.JASN1Converter;
import org.apache.nifi.jasn1.convert.JASN1TypeAndValueConverter;
import org.apache.nifi.serialization.record.DataType;
import org.apache.nifi.serialization.record.RecordFieldType;
public class TbcdStringConverter implements JASN1TypeAndValueConverter {
private static final String TBCD_STRING_TYPE = "TBCDSTRING";
private static final char[] TBCD_SYMBOLS = "0123456789*#abc".toCharArray();
private static final int FILLER_DECIMAL_CODE = 15;
@Override
public boolean supportsType(Class<?> berType) {
boolean supportsType = BerOctetString.class.isAssignableFrom(berType) && isTbcdString(berType);
return supportsType;
}
@Override
public DataType convertType(Class<?> berType, JASN1Converter converter) {
DataType dataType = RecordFieldType.STRING.getDataType();
return dataType;
}
@Override
public boolean supportsValue(BerType value, DataType dataType) {
boolean supportsValue = value instanceof BerOctetString && isTbcdString(value.getClass());
return supportsValue;
}
@Override
public Object convertValue(BerType value, DataType dataType, JASN1Converter converter) {
final BerOctetString berValue = ((BerOctetString) value);
byte[] bytes = berValue.value;
int size = (bytes == null ? 0 : bytes.length);
StringBuilder resultBuilder = new StringBuilder(2 * size);
for (int octetIndex = 0; octetIndex < size; ++octetIndex) {
int octet = bytes[octetIndex];
int digit2 = (octet >> 4) & 0xF;
int digit1 = octet & 0xF;
if (digit1 == FILLER_DECIMAL_CODE) {
invalidFiller(octetIndex, octet);
} else if (digit1 > 15) {
invalidInteger(digit1);
} else {
resultBuilder.append(TBCD_SYMBOLS[digit1]);
}
if (digit2 == FILLER_DECIMAL_CODE) {
if (octetIndex != size - 1) {
invalidFiller(octetIndex, octet);
}
} else if (digit2 > 15) {
invalidInteger(digit2);
} else {
resultBuilder.append(TBCD_SYMBOLS[digit2]);
}
}
return resultBuilder.toString();
}
private boolean isTbcdString(Class<?> berType) {
Class<?> currentType = berType;
while (currentType != null) {
if (currentType.getSimpleName().equals(TBCD_STRING_TYPE)) {
return true;
}
currentType = currentType.getSuperclass();
}
return false;
}
private void invalidFiller(int octetIndex, int octet) {
throw new NumberFormatException("Illegal filler in octet " + octetIndex + ": " + octet);
}
private void invalidInteger(int digit) {
throw new IllegalArgumentException(
"Integer should be between 0 - 15 for Telephony Binary Coded Decimal String. Received " + digit);
}
}

View File

@ -25,6 +25,8 @@ import com.beanit.asn1bean.ber.types.string.BerUTF8String;
import org.apache.nifi.jasn1.example.BasicTypeSet;
import org.apache.nifi.jasn1.example.BasicTypes;
import org.apache.nifi.jasn1.example.Composite;
import org.apache.nifi.jasn1.tbcd.TBCDSTRING;
import org.apache.nifi.jasn1.tbcd.TbcdStringWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -52,6 +54,8 @@ public class ExampleDataGenerator {
generateComposite(dir);
generateMultiRecord(dir);
generateTbcdString(dir);
}
private static void generateBasicTypes(File dir) throws IOException {
@ -143,4 +147,17 @@ public class ExampleDataGenerator {
return encoded;
}
private static void generateTbcdString(File dir) throws IOException {
final File file = new File(dir, "tbcd-string.dat");
try (final ReverseByteArrayOutputStream rev = new ReverseByteArrayOutputStream(1024);
final OutputStream out = new FileOutputStream(file)) {
final TbcdStringWrapper tbcdStringWrapper = new TbcdStringWrapper();
tbcdStringWrapper.setTbcdString(new TBCDSTRING(new byte[]{1, 2, 3, 4, 5, 6, 7, 8}));
tbcdStringWrapper.setOctetString(new BerOctetString(new byte[]{1, 2, 3, 4, 5, 6, 7, 8}));
final int encoded = tbcdStringWrapper.encode(rev);
out.write(rev.getArray(), 0, encoded);
LOG.info("Generated {} bytes to {}", encoded, file);
}
}
}

View File

@ -153,4 +153,23 @@ public class TestJASN1RecordReader implements JASN1ReadRecordTester {
assertNull(record3);
}
}
@Test
public void testTbcdString() throws Exception {
try (final InputStream input = TestJASN1RecordReader.class.getResourceAsStream("/examples/tbcd-string.dat")) {
final JASN1RecordReader reader = new JASN1RecordReader("org.apache.nifi.jasn1.tbcd.TbcdStringWrapper", null,
new RecordSchemaProvider(), Thread.currentThread().getContextClassLoader(), null,
input, new MockComponentLog("id", new JASN1Reader()));
final RecordSchema schema = reader.getSchema();
assertEquals("TbcdStringWrapper", schema.getSchemaName().orElse(null));
Record record = reader.nextRecord(true, false);
assertNotNull(record);
record = reader.nextRecord(true, false);
assertNull(record);
}
}
}

View File

@ -0,0 +1 @@
0<14><08>

View File

@ -0,0 +1,22 @@
ORG-APACHE-NIFI-JASN1-TBCD
DEFINITIONS IMPLICIT TAGS ::=
BEGIN
TbcdStringWrapper ::= SEQUENCE
{
tbcdString [0] TBCD-STRING,
octetString [1] OCTET STRING (SIZE (4..255))
}
TBCD-STRING ::= OCTET STRING
-- This type (Telephony Binary Coded Decimal String) is used to
-- represent several digits from 0 through 9, *, #, a, b , c, two
-- digits per octet, each digit encoded 0000 to 1001 (0 to 9),
-- 1010 (*), 1011 (#), 1100 (a), 1101 (b) or 1110 (c); 1111 used
-- as filler when there is an odd number of digits.
-- bits 8765 of octet n encoding digit 2n
-- bits 4321 of octet n encoding digit 2(n-1) 1
END