diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml index 732ac5e4c2..706b88899a 100644 --- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml @@ -92,6 +92,7 @@ ${basedir}/src/test/resources/simple_types.asn ${basedir}/src/test/resources/complex_types.asn ${basedir}/src/test/resources/example.asn + ${basedir}/src/test/resources/tbcd_string.asn -o ${basedir}/target/generated-test-sources @@ -128,8 +129,10 @@ src/test/resources/example.asn src/test/resources/simple_types.asn src/test/resources/complex_types.asn + src/test/resources/tbcd_string.asn src/test/resources/examples/basic-types.dat src/test/resources/examples/composite.dat + src/test/resources/examples/tbcd-string.dat diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java index 4c52b79ac7..fc684d0f98 100644 --- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java @@ -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) diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/TbcdStringConverter.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/TbcdStringConverter.java new file mode 100644 index 0000000000..5596ff2179 --- /dev/null +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/TbcdStringConverter.java @@ -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); + } +} diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java index f73ad45ab4..5296d5bfa6 100644 --- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java @@ -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); + } + } } diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java index c1fb12c24d..129d5bac39 100644 --- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java @@ -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); + } + } } diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/examples/tbcd-string.dat b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/examples/tbcd-string.dat new file mode 100644 index 0000000000..18097ce68d --- /dev/null +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/examples/tbcd-string.dat @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/tbcd_string.asn b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/tbcd_string.asn new file mode 100644 index 0000000000..d5802a531c --- /dev/null +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/tbcd_string.asn @@ -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 \ No newline at end of file