apache-camelbindy

How can I handle fixedLengthformat data?


I handle some data with fixed length. So I use bindy component for treating this data.

This file has only one record. The record has header, multi bodies, and footer.

  header record (total length : 20)
  1 : record_type (length : 1)
  VOLTE : service_type (length : 5)
  20190515 : creation date (length : 8)
  3 : custom_flag (length : 6)

  3 body records (total length : 20)
  2 : record_type (length : 1)
  01012345678 : mobile number (length : 11)
  20190515 : call start date (length : 8)

  footer records (total length : 20)
  3 : record_type (length : 1)
  AAAA.DAT : FILE NAME (length : 19)

Real Data

  1VOLTE20190515     32010123456782019051520101234567820190516201012345678201905173AAAA.DAT           

I defined dataformat like below.

Header

  @FixedLengthRecord(length=20, paddingChar=' ')
  public class VoLTEHeader {

  @DataField(pos=1, length=1, trim=true)
  String record_type;

  @DataField(pos=2, length=5, trim=true)
  String service_type;

  @DataField(pos=7, length=8, trim=true)
  String creation_date;

  @DataField(pos=15, length=6, trim=true, align="R")
  String custom_flag;

Footer

  @FixedLengthRecord(length=20, paddingChar=' ')
  public class VoLTEFooter {

  @DataField(pos=1, length=1, trim=true)
  String record_type;

  @DataField(pos=2, length=19, trim=true)
  String file_name;

Body

  @FixedLengthRecord(length=20, header=VoLTEHeader.class, footer=VoLTEFooter.class)
  public class VoLTEBody implements Serializable {

  @DataField(pos=1, length=1,trim=true)
  String record_type;

  @DataField(pos=2, length=11,trim=true)
  String mobile_number;

  @DataField(pos=13, length=8,trim=true)
  String call_start_date;

I executed camel route but the exception is occurred.

  java.lang.IllegalArgumentException: Size of the record: 100 is not equal to the value provided in the model: 20
  at org.apache.camel.dataformat.bindy.fixed.BindyFixedLengthDataFormat.createModel(BindyFixedLengthDataFormat.java:295) ~[camel-bindy-2.23.2.jar:2.23.2]
at org.apache.camel.dataformat.bindy.fixed.BindyFixedLengthDataFormat.unmarshal(BindyFixedLengthDataFormat.java:209) ~[camel-bindy-2.23.2.jar:2.23.2]
at org.apache.camel.processor.UnmarshalProcessor.process(UnmarshalProcessor.java:69) ~[camel-core-2.23.2.jar:2.23.2]
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548) [camel-core-2.23.2.jar:2.23.2]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201) [camel-core-2.23.2.jar:2.23.2]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:138) [camel-core-2.23.2.jar:2.23.2]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:101) [camel-core-2.23.2.jar:2.23.2]

I don't think that fixedLengthDataFormat necessarily needs to be created in multiple lines.

How can I fix this issue?


Solution

  • Thank you. I implemented it though your guidance. I think that Bindy component support header, footer and body.

    So, I considered below logic.

    Incoming file -> split (20 length) -> aggregating split file -> unmarshalling

    I use aggregated file with header, footer and bodies.

    Below is code.

      from("direct:start")
                        // assuming the raw record is in the body, we keep a copy in a Camel-header
                        .setHeader("record", body())
                        .setBody().groovy("request.body.split('(?<=\\\\G.{20})')")
                        .split(body(), AggregationStrategies.flexible().storeInHeader("bodyList").accumulateInCollection(ArrayList.class))
                        .unmarshal(bindyOneBody)
                        .end()
                        .log("VoLTEBody*: ${header.bodyList}")
                       ...
    

    VoLTEBody

           @FixedLengthRecord(length=20, header=VoLTEHeader.class, footer=VoLTETailer.class)
           public class VoLTEBody {
    
           @DataField(pos=1, length=1,trim=true)
           String record_type;
    

    But there are errors like below.

           Stacktrace
           ------------------------------------------------------------------------------ 
           --------------------------------------------------------- 
           java.lang.IllegalArgumentException: No records have been defined in the file
                   at org.apache.camel.dataformat.bindy.fixed.BindyFixedLengthDataFormat.unmarshal(BindyFixedLengthDataFormat.java:250) ~[camel-bindy-2.23.2.jar:2.23.2]
                   at org.apache.camel.processor.UnmarshalProcessor.process(UnmarshalProcessor.java:69) ~[camel-core-2.23.2.jar:2.23.2]
                   at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548) [camel-core-2.23.2.jar:2.23.2]
                   at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201) [camel-core-2.23.2.jar:2.23.2]
                   at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548) [camel-core-2.23.2.jar:2.23.2]
    

    I think that this process is fine if annotation about header and footer is correctly defined in VoLTEBody class.

    How can I handle this issue?

    Additionally, I executed another test. In this case, there is no split.

    Incoming file -> unmarshalling (bindyOneBody)

    Router

        from("direct:start")
                        // assuming the raw record is in the body, we keep a copy in a Camel-header
                        .setHeader("record", body())
                        //.setBody().groovy("request.body.split('(?<=\\\\G.{20})')")
                        //.split(body(), AggregationStrategies.flexible().storeInHeader("bodyList").accumulateInCollection(ArrayList.class))
                        .unmarshal(bindyOneBody)
    

    There is below result. In this result, we cannot find VoLTEHeader and VoLTEFooter structures. This is fine.

         2019-05-16 15:22:15,798 DEBUG BindyFixedLengthDataFormat - Graph of objects created: {camel.dataformat.volte.VoLTEBody_sample=VoLTEBody[record_type=2, mobile_number=01012345678, call_start_date=20190517]} 
         2019-05-16 15:22:15,798 INFO  route1 - [VoLTEBody[record_type=2, mobile_number=01012345678, call_start_date=20190515], VoLTEBody[record_type=2, mobile_number=01012345678, call_start_date=20190516], VoLTEBody[record_type=2, mobile_number=01012345678, call_start_date=20190517]] 
         2019-05-16 15:22:15,798 INFO  MyRouteBuilderTest - ********************************************************************************