Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Asn1EncodedDataRouter to use Spring Kafka #138

Draft
wants to merge 128 commits into
base: dev
Choose a base branch
from

Conversation

mcook42
Copy link

@mcook42 mcook42 commented Dec 24, 2024

PR Details

Description

  • Migrated Asn1EncodedDataRouter to use Spring Kafka instead of homegrown Kafka implementation
  • Changed from swallowing all exceptions to explicitly handling the non-critical exceptions (where we can reasonably continue to process the data) and throwing specific exceptions where we cannot continue processing (where missing data would cause unexpected downstream issues)
  • Removed duplicated logging wherever EventLogger was used
  • Moved OdeTimJsonTopology to a Spring Configuration class to enable dependency injection for testing and Asn1DecodedDataRouter listener Bean initialization
  • Extracted interactions with the security services module into SecurityServicesClient and defined the request and response models based on the raw JSON manipulation done prior
  • Deleted Asn1CommandManager and moved logic to the Asn1EncodedDataRouter for clearer code and fewer classes to maintain
  • Moved class creation out of Asn1EncodedDataRouter into the relevant Beans to enable easier testing with Spring Dependency Injection
  • Replaced outdated (and buggy) usage of the Date class with usages of LocalDateTime (only in Asn1EncodedDataRouter) to allow for explicit usage of UTC timezone instead of relying on the system settings (they aren't consistent between local and CI, so it's reasonable to suspect there is inconsistency between hosting environments)

Related Issue

No related USDOT issue

Motivation and Context

Implementing Spring Kafka gives us better lifecycle management of producers and consumers, more reusable producer/consumer code, easier testability, and a more robust production-ready Kafka library. This is part of a more significant effort to replace our hand-rolled Kafka implementation with Spring Kafka. The previous changesets related to this effort are:

How Has This Been Tested?

  • Before making any code changes, I refactored the Asn1EncodedDataRouter class to check the output to the different topics is as expected.
  • Refactored Asn1EncodedDataRouter class to use Spring Kafka and confirmed the tests continued to behave as expected
  • I sent the data from the udpsender_[msgType].py scripts found under scripts/tests through a live local system started up with make rebuild. I confirmed there were no errors in the logs. I also confirmed that all expected messages were produced to and consumed from the correct queues by using the kafka-ui container available at localhost:8001 (on my local machine, of course).

For the live testing, I set the following environment variables on my system to enable signing and confirm all pieces played well together

DATA_SIGNING_ENABLED_RSU=true
DATA_SIGNING_ENABLED_SDW=true

Snippet from the logs during local testing:

2024-12-27 14:14:48 2024-12-27 21:14:48 [UdpReceiverManager] DEBUG UdpHexDecoder - Packet received from 172.18.0.1:56852 
2024-12-27 14:14:48 2024-12-27 21:14:48 [UdpReceiverManager] DEBUG UdpHexDecoder - Full TIM packet: 005f498718cca69ec1a04600000100105d9b46ec5be401003a0103810040038081d4001f80d07016da410000000000000bbc2b0f775d9b0309c271431fa166ee0a27fff93f136b8205a0a107fb2ef979f4c5bfaeec97e4ad70c2fb36cd9730becdb355cc2fd2a7556b160b98b46ab98ae62c185fa55efb468d5b4000000004e2863f42cddc144ff7980040401262cdd7b809c509f5c62cdd35519c507b9062cdcee129c505cf262cdca5ff9c50432c62cdc5d3d9c502e3e62cdc13e79c501e9262cdbca2d9c5013ee62cdb80359c500e6a62cdb36299c500bc862cdaec1d9c50093c62cdaa2109c5006ea1080203091a859eeebb36006001830001aad27f4ff7580001aad355e39b5880a30029d6585009ef808332d8d9f80c3855151b38c772f765007967ec1170bcb7937f5cb880a25a52863493bcb87570dbcb5abc6bfb2faec606cfa34eb95a24790b2017366d3aabe7729e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 
2024-12-27 14:14:48 2024-12-27 21:14:48 [UdpReceiverManager] DEBUG UperUtil - Base payload: 001f80d07016da410000000000000bbc2b0f775d9b0309c271431fa166ee0a27fff93f136b8205a0a107fb2ef979f4c5bfaeec97e4ad70c2fb36cd9730becdb355cc2fd2a7556b160b98b46ab98ae62c185fa55efb468d5b4000000004e2863f42cddc144ff7980040401262cdd7b809c509f5c62cdd35519c507b9062cdcee129c505cf262cdca5ff9c50432c62cdc5d3d9c502e3e62cdc13e79c501e9262cdbca2d9c5013ee62cdb80359c500e6a62cdb36299c500bc862cdaec1d9c50093c62cdaa2109c5006ea1080203091a859eeebb36006001830001aad27f4ff7580001aad355e39b5880a30029d6585009ef808332d8d9f80c3855151b38c772f765007967ec1170bcb7937f5cb880a25a52863493bcb87570dbcb5abc6bfb2faec606cfa34eb95a24790b2017366d3aabe7729e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 
2024-12-27 14:14:48 2024-12-27 21:14:48 [UdpReceiverManager] DEBUG UperUtil - Stripped payload: 001f80d07016da410000000000000bbc2b0f775d9b0309c271431fa166ee0a27fff93f136b8205a0a107fb2ef979f4c5bfaeec97e4ad70c2fb36cd9730becdb355cc2fd2a7556b160b98b46ab98ae62c185fa55efb468d5b4000000004e2863f42cddc144ff7980040401262cdd7b809c509f5c62cdd35519c507b9062cdcee129c505cf262cdca5ff9c50432c62cdc5d3d9c502e3e62cdc13e79c501e9262cdbca2d9c5013ee62cdb80359c500e6a62cdb36299c500bc862cdaec1d9c50093c62cdaa2109c5006ea1080203091a859eeebb36006001830001aad27f4ff7580001aad355e39b5880a30029d6585009ef808332d8d9f80c3855151b38c772f765007967ec1170bcb7937f5cb880a25a52863493bcb87570dbcb5abc6bfb2faec606cfa34eb95a24790b2017366d3aabe7729e00 
2024-12-27 14:14:48 2024-12-27 21:14:48 [UdpReceiverManager] DEBUG UdpHexDecoder - Stripped TIM packet: 03810040038081d4001f80d07016da410000000000000bbc2b0f775d9b0309c271431fa166ee0a27fff93f136b8205a0a107fb2ef979f4c5bfaeec97e4ad70c2fb36cd9730becdb355cc2fd2a7556b160b98b46ab98ae62c185fa55efb468d5b4000000004e2863f42cddc144ff7980040401262cdd7b809c509f5c62cdd35519c507b9062cdcee129c505cf262cdca5ff9c50432c62cdc5d3d9c502e3e62cdc13e79c501e9262cdbca2d9c5013ee62cdb80359c500e6a62cdb36299c500bc862cdaec1d9c50093c62cdaa2109c5006ea1080203091a859eeebb36006001830001aad27f4ff7580001aad355e39b5880a30029d6585009ef808332d8d9f80c3855151b38c772f765007967ec1170bcb7937f5cb880a25a52863493bcb87570dbcb5abc6bfb2faec606cfa34eb95a24790b2017366d3aabe7729e00 
2024-12-27 14:14:48 2024-12-27 21:14:48 [UdpReceiverManager] DEBUG TimReceiver - Waiting for UDP TIM packets... 
2024-12-27 14:14:48 2024-12-27 21:14:48 [kafka-producer-network-thread | producer-5] DEBUG LoggingProducerListener - Successfully produced to topic topic.OdeRawEncodedTIMJson with key 81787258-c75b-4cb5-9d8f-1cc6d998573c_1.0.0#0 and value {"metadata":{"recordType":"timMsg","securityResultCode":"success","payloadType":"us.dot.its.jpo.ode.model.OdeAsn1Payload","serialId":{"streamId":"81787258-c75b-4cb5-9d8f-1cc6d998573c","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"2024-12-27T21:14:48.007Z","schemaVersion":7,"maxDurationTime":0,"recordGeneratedBy":"RSU","sanitized":false,"asn1":"03810040038081D4001F80D07016DA410000000000000BBC2B0F775D9B0309C271431FA166EE0A27FFF93F136B8205A0A107FB2EF979F4C5BFAEEC97E4AD70C2FB36CD9730BECDB355CC2FD2A7556B160B98B46AB98AE62C185FA55EFB468D5B4000000004E2863F42CDDC144FF7980040401262CDD7B809C509F5C62CDD35519C507B9062CDCEE129C505CF262CDCA5FF9C50432C62CDC5D3D9C502E3E62CDC13E79C501E9262CDBCA2D9C5013EE62CDB80359C500E6A62CDB36299C500BC862CDAEC1D9C50093C62CDAA2109C5006EA1080203091A859EEEBB36006001830001AAD27F4FF7580001AAD355E39B5880A30029D6585009EF808332D8D9F80C3855151B38C772F765007967EC1170BCB7937F5CB880A25A52863493BCB87570DBCB5ABC6BFB2FAEC606CFA34EB95A24790B2017366D3AABE7729E00","originIp":"172.18.0.1"},"payload":{"dataType":"us.dot.its.jpo.ode.model.OdeHexByteArray","data":{"bytes":"03810040038081D4001F80D07016DA410000000000000BBC2B0F775D9B0309C271431FA166EE0A27FFF93F136B8205A0A107FB2EF979F4C5BFAEEC97E4AD70C2FB36CD9730BECDB355CC2FD2A7556B160B98B46AB98AE62C185FA55EFB468D5B4000000004E2863F42CDDC144FF7980040401262CDD7B809C509F5C62CDD35519C507B9062CDCEE129C505CF262CDCA5FF9C50432C62CDC5D3D9C502E3E62CDC13E79C501E9262CDBCA2D9C5013EE62CDB80359C500E6A62CDB36299C500BC862CDAEC1D9C50093C62CDAA2109C5006EA1080203091A859EEEBB36006001830001AAD27F4FF7580001AAD355E39B5880A30029D6585009EF808332D8D9F80C3855151B38C772F765007967EC1170BCB7937F5CB880A25A52863493BCB87570DBCB5ABC6BFB2FAEC606CFA34EB95A24790B2017366D3AABE7729E00"}}}  
2024-12-27 14:14:48 2024-12-27 21:14:48 [kafka-producer-network-thread | producer-6] DEBUG LoggingProducerListener - Successfully produced to topic topic.Asn1DecoderInput with key 81787258-c75b-4cb5-9d8f-1cc6d998573c_1.0.0#0 and value {"metadata":{"recordType":"timMsg","securityResultCode":"success","encodings":[{"elementName":"unsecuredData","elementType":"MessageFrame","encodingRule":"UPER"}],"payloadType":"us.dot.its.jpo.ode.model.OdeAsn1Payload","serialId":{"streamId":"81787258-c75b-4cb5-9d8f-1cc6d998573c","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"2024-12-27T21:14:48.007Z","schemaVersion":7,"maxDurationTime":0,"recordGeneratedBy":"RSU","sanitized":false,"asn1":"03810040038081D4001F80D07016DA410000000000000BBC2B0F775D9B0309C271431FA166EE0A27FFF93F136B8205A0A107FB2EF979F4C5BFAEEC97E4AD70C2FB36CD9730BECDB355CC2FD2A7556B160B98B46AB98AE62C185FA55EFB468D5B4000000004E2863F42CDDC144FF7980040401262CDD7B809C509F5C62CDD35519C507B9062CDCEE129C505CF262CDCA5FF9C50432C62CDC5D3D9C502E3E62CDC13E79C501E9262CDBCA2D9C5013EE62CDB80359C500E6A62CDB36299C500BC862CDAEC1D9C50093C62CDAA2109C5006EA1080203091A859EEEBB36006001830001AAD27F4FF7580001AAD355E39B5880A30029D6585009EF808332D8D9F80C3855151B38C772F765007967EC1170BCB7937F5CB880A25A52863493BCB87570DBCB5ABC6BFB2FAEC606CFA34EB95A24790B2017366D3AABE7729E00","originIp":"172.18.0.1"},"payload":{"dataType":"us.dot.its.jpo.ode.model.OdeHexByteArray","data":{"bytes":"001F80D07016DA410000000000000BBC2B0F775D9B0309C271431FA166EE0A27FFF93F136B8205A0A107FB2EF979F4C5BFAEEC97E4AD70C2FB36CD9730BECDB355CC2FD2A7556B160B98B46AB98AE62C185FA55EFB468D5B4000000004E2863F42CDDC144FF7980040401262CDD7B809C509F5C62CDD35519C507B9062CDCEE129C505CF262CDCA5FF9C50432C62CDC5D3D9C502E3E62CDC13E79C501E9262CDBCA2D9C5013EE62CDB80359C500E6A62CDB36299C500BC862CDAEC1D9C50093C62CDAA2109C5006EA1080203091A859EEEBB36006001830001AAD27F4FF7580001AAD355E39B5880A30029D6585009EF808332D8D9F80C3855151B38C772F765007967EC1170BCB7937F5CB880A25A52863493BCB87570DBCB5ABC6BFB2FAEC606CFA34EB95A24790B2017366D3AABE7729E00"}}}  
2024-12-27 14:14:48 2024-12-27 21:14:48 [Asn1DecodedDataRouter-0-C-1] DEBUG Asn1DecodedDataRouter - Key: null payload: <?xml version="1.0"?><OdeAsn1Data><metadata><logFileName/><recordType>timMsg</recordType><securityResultCode>success</securityResultCode><receivedMessageDetails/><encodings><encodings><elementName>unsecuredData</elementName><elementType>MessageFrame</elementType><encodingRule>UPER</encodingRule></encodings></encodings><payloadType>us.dot.its.jpo.ode.model.OdeAsn1Payload</payloadType><serialId><streamId>81787258-c75b-4cb5-9d8f-1cc6d998573c</streamId><bundleSize>1</bundleSize><bundleId>0</bundleId><recordId>0</recordId><serialNumber>0</serialNumber></serialId><odeReceivedAt>2024-12-27T21:14:48.007Z</odeReceivedAt><schemaVersion>7</schemaVersion><maxDurationTime>0</maxDurationTime><recordGeneratedAt/><recordGeneratedBy>RSU</recordGeneratedBy><sanitized>false</sanitized><odePacketID/><odeTimStartDateTime/><asn1>03810040038081D4001F80D07016DA410000000000000BBC2B0F775D9B0309C271431FA166EE0A27FFF93F136B8205A0A107FB2EF979F4C5BFAEEC97E4AD70C2FB36CD9730BECDB355CC2FD2A7556B160B98B46AB98AE62C185FA55EFB468D5B4000000004E2863F42CDDC144FF7980040401262CDD7B809C509F5C62CDD35519C507B9062CDCEE129C505CF262CDCA5FF9C50432C62CDC5D3D9C502E3E62CDC13E79C501E9262CDBCA2D9C5013EE62CDB80359C500E6A62CDB36299C500BC862CDAEC1D9C50093C62CDAA2109C5006EA1080203091A859EEEBB36006001830001AAD27F4FF7580001AAD355E39B5880A30029D6585009EF808332D8D9F80C3855151B38C772F765007967EC1170BCB7937F5CB880A25A52863493BCB87570DBCB5ABC6BFB2FAEC606CFA34EB95A24790B2017366D3AABE7729E00</asn1><originIp>172.18.0.1</originIp></metadata><payload><dataType>MessageFrame</dataType><data><MessageFrame><messageId>31</messageId><value><TravelerInformation><msgCnt>1</msgCnt><timeStamp>449089</timeStamp><packetID>0000000000000BBC2B</packetID><urlB>null</urlB><dataFrames><TravelerDataFrame><notUsed>1</notUsed><frameType><advisory/></frameType><msgId><roadSignID><position><lat>411269876</lat><long>-1047269563</long></position><viewAngle>1111111111111111</viewAngle><mutcdCode><warning/></mutcdCode></roadSignID></msgId><startYear>2018</startYear><startTime>448260</startTime><durationTime>1440</durationTime><priority>5</priority><notUsed1>1</notUsed1><regions><GeographicalPath><name>westbound_I-80_366.0_365.0_RSU-10.145.1.100_RW_4456</name><id><region>0</region><id>0</id></id><anchor><lat>411269876</lat><long>-1047269563</long></anchor><laneWidth>32700</laneWidth><directionality><both/></directionality><closedPath><false/></closedPath><direction>0000000000010000</direction><description><path><scale>0</scale><offset><xy><nodes><NodeXY><delta><node-LatLon><lon>-1047287423</lon><lat>411264686</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047305390</lon><lat>411260104</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047323629</lon><lat>411256185</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047342080</lon><lat>411252886</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047360706</lon><lat>411250207</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047379480</lon><lat>411248201</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047398354</lon><lat>411246839</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047417290</lon><lat>411246133</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047436246</lon><lat>411245796</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047455202</lon><lat>411245470</lat></node-LatLon></delta></NodeXY><NodeXY><delta><node-LatLon><lon>-1047474159</lon><lat>411245173</lat></node-LatLon></delta></NodeXY></nodes></xy></offset></path></description></GeographicalPath></regions><notUsed2>1</notUsed2><notUsed3>1</notUsed3><content><advisory><SEQUENCE><item><itis>777</itis></item></SEQUENCE><SEQUENCE><item><itis>13579</itis></item></SEQUENCE></advisory></content><url>null</url></TravelerDataFrame></dataFrames></TravelerInformation></value></MessageFrame></data></payload></OdeAsn1Data> 
2024-12-27 14:14:48 2024-12-27 21:14:48 [kafka-producer-network-thread | producer-5] DEBUG LoggingProducerListener - Successfully produced to topic topic.OdeTimJson with key 81787258-c75b-4cb5-9d8f-1cc6d998573c and value {"metadata":{"logFileName":"","recordType":"timMsg","securityResultCode":"success","receivedMessageDetails":{"rxSource":"NA"},"payloadType":"us.dot.its.jpo.ode.model.OdeTimPayload","serialId":{"streamId":"81787258-c75b-4cb5-9d8f-1cc6d998573c","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"2024-12-27T21:14:48.007Z","schemaVersion":7,"maxDurationTime":0,"recordGeneratedAt":"","recordGeneratedBy":"RSU","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","asn1":"03810040038081D4001F80D07016DA410000000000000BBC2B0F775D9B0309C271431FA166EE0A27FFF93F136B8205A0A107FB2EF979F4C5BFAEEC97E4AD70C2FB36CD9730BECDB355CC2FD2A7556B160B98B46AB98AE62C185FA55EFB468D5B4000000004E2863F42CDDC144FF7980040401262CDD7B809C509F5C62CDD35519C507B9062CDCEE129C505CF262CDCA5FF9C50432C62CDC5D3D9C502E3E62CDC13E79C501E9262CDBCA2D9C5013EE62CDB80359C500E6A62CDB36299C500BC862CDAEC1D9C50093C62CDAA2109C5006EA1080203091A859EEEBB36006001830001AAD27F4FF7580001AAD355E39B5880A30029D6585009EF808332D8D9F80C3855151B38C772F765007967EC1170BCB7937F5CB880A25A52863493BCB87570DBCB5ABC6BFB2FAEC606CFA34EB95A24790B2017366D3AABE7729E00","originIp":"172.18.0.1"},"payload":{"data":{"msgCnt":1,"timeStamp":449089,"packetID":"0000000000000BBC2B","urlB":"null","dataFrames":[{"doNotUse1":1,"frameType":"advisory","msgId":{"roadSignID":{"position":{"lat":411269876,"long":-1047269563},"viewAngle":{"from000-0to022-5degrees":true,"from022-5to045-0degrees":true,"from045-0to067-5degrees":true,"from067-5to090-0degrees":true,"from090-0to112-5degrees":true,"from112-5to135-0degrees":true,"from135-0to157-5degrees":true,"from157-5to180-0degrees":true,"from180-0to202-5degrees":true,"from202-5to225-0degrees":true,"from225-0to247-5degrees":true,"from247-5to270-0degrees":true,"from270-0to292-5degrees":true,"from292-5to315-0degrees":true,"from315-0to337-5degrees":true,"from337-5to360-0degrees":true},"mutcdCode":"warning"}},"startYear":2018,"startTime":448260,"durationTime":1440,"priority":5,"doNotUse2":1,"regions":[{"name":"westbound_I-80_366.0_365.0_RSU-10.145.1.100_RW_4456","id":{"region":0,"id":0},"anchor":{"lat":411269876,"long":-1047269563},"laneWidth":32700,"directionality":"both","closedPath":false,"direction":{"from000-0to022-5degrees":false,"from022-5to045-0degrees":false,"from045-0to067-5degrees":false,"from067-5to090-0degrees":false,"from090-0to112-5degrees":false,"from112-5to135-0degrees":false,"from135-0to157-5degrees":false,"from157-5to180-0degrees":false,"from180-0to202-5degrees":false,"from202-5to225-0degrees":false,"from225-0to247-5degrees":false,"from247-5to270-0degrees":true,"from270-0to292-5degrees":false,"from292-5to315-0degrees":false,"from315-0to337-5degrees":false,"from337-5to360-0degrees":false},"description":{"path":{"scale":0,"offset":{"xy":{"nodes":[{"delta":{"node-LatLon":{"lon":-1047287423,"lat":411264686}}},{"delta":{"node-LatLon":{"lon":-1047305390,"lat":411260104}}},{"delta":{"node-LatLon":{"lon":-1047323629,"lat":411256185}}},{"delta":{"node-LatLon":{"lon":-1047342080,"lat":411252886}}},{"delta":{"node-LatLon":{"lon":-1047360706,"lat":411250207}}},{"delta":{"node-LatLon":{"lon":-1047379480,"lat":411248201}}},{"delta":{"node-LatLon":{"lon":-1047398354,"lat":411246839}}},{"delta":{"node-LatLon":{"lon":-1047417290,"lat":411246133}}},{"delta":{"node-LatLon":{"lon":-1047436246,"lat":411245796}}},{"delta":{"node-LatLon":{"lon":-1047455202,"lat":411245470}}},{"delta":{"node-LatLon":{"lon":-1047474159,"lat":411245173}}}]}}}}}],"doNotUse3":1,"doNotUse4":1,"content":{"advisory":[{"item":{"itis":777}},{"item":{"itis":13579}}]},"url":"null"}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.travelerinformation.TravelerInformation"}}

Types of changes

  • Defect fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that cause existing functionality to change)

Checklist:

  • I have added any new packages to the sonar-scanner.properties file
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
    ODE Contributing Guide
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Helpful Documentation

Generated by sending tim to deposit tim endpoint and grabbing value produced to the `topic.Asn1EncoderOutput` topic via kafka-ui
…TimUnsecured_depositsToSdxTopicAndTimTmcFiltered
…tImpl

These can be used to wrap the calls to security services and allow easier mocking of responses. It also allows us to better shield ourselves from API contract changes. users of the client don't need to be aware of changes to the external API as all interactions can be encapsulated within the client
This moves the calls to security services from Asn1CommandManager to SecurityServicesClientImpl which allows for more testability, flexibility (mocking client calls), and modularity
The responsibility to submit data to topics is already contained within Asn1EncodedDataRouter, and Asn1CommandManager is not responsible for any kafka interactions otherwise, so the responsibility was moved to Asn1EncodedDataRouter
Updated method signatures and instance usage to specify ResponseEvent with Address as the generic type. This change improves type safety and aligns with best practices for clearer code readability and maintainability.
Refactored the SecurityServicesClient to use dependency-injected RestTemplate and improved the request payload structure with a dedicated SignatureRequestModel class. Added unit tests for signMessage functionality and introduced configuration for RestTemplate with WebClientConfig.
Added `RestClientException` to `signMessage` for better error handling. Implemented a new test case to verify behavior when the signing service returns a null response.
Simplified `getServiceRequest` method by directly passing the metadata JSON object instead of the full consumed object. Updated relevant calls to align with this change, improving clarity and reducing redundant operations.
Removed verbose and redundant JavaDoc comments, replacing them with concise inline comments to improve code readability. This change ensures that key processing logic remains documented without unnecessary detail duplication.
@mcook42 mcook42 force-pushed the mcook42/spring-kafka/asn1-encoded-router branch from 0bc948a to 0d30254 Compare December 26, 2024 23:56
Removed redundant null checks before calling `sendToRsus` in the main logic. The null checks are properly handled within the `sendToRsus` method, ensuring clearer and more maintainable code.
Standardizing on the ObjectMapper provided in the app context will reduce variability and decrease risk of unintended differences in serdes behavior
This name better represents the behavior of the method. The Javadocs were updated to be accurate as well
Copy link
Author

@mcook42 mcook42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend reviewing the Asn1EncodedDataRouter code from within your IDE. There are a lot of changes in there that don't necessarily work well with GitHub's viewer. The processing flow should not have changed. The changes in that file should be in one of four categories:

  1. Deduplication of JSON processing
  2. Deduplication of message signing or encoding
  3. Using the SerializationConfig-provided Object Mapper instead of JsonUtils or TimTransmorgrifier or other JSON serdes (there were a few weird ones).
  4. Extracting logic into named methods to reduce cognitive complexity

Comment on lines -61 to +55
return streams.state().isRunningOrRebalancing();
return streams.state().equals(KafkaStreams.State.RUNNING);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this method is only used in tests for now, and in the tests, a state of REBALANCING would cause an error. Addressing this possible bug may be worth the effort in a follow-up PR or separate work item. Still, I don't believe the changes belong here since I didn't change how the OdeTimJsonTopology works in this PR.

Comment on lines -169 to +180
kafkaTemplate.send(jsonTopics.getTim(), consumerRecord.key(), odeTimData);
kafkaTemplate.send(jsonTopics.getTim(), streamId, odeTimData);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: the key is empty when consuming from the asn1 decoder output topic. We need to include the streamId as the key when publishing TIM data so that the downstream consumers can use the streamId to lookup the TIM JSON from the K-Table in OdeTimJsonTopology. If we don't produce with a streamId (which we conditionally set a few lines above this method)) then we will never produce to the TMCFiltered topic in the Asn1EncodedDataRouter

Comment on lines -131 to -156
if (metadata.has(TimTransmogrifier.REQUEST_STRING)) {
JSONObject request = metadata.getJSONObject(TimTransmogrifier.REQUEST_STRING);
if (request.has(TimTransmogrifier.RSUS_STRING)) {
Object rsus = request.get(TimTransmogrifier.RSUS_STRING);
if (rsus instanceof JSONObject) {
JSONObject rsusIn = (JSONObject) request.get(TimTransmogrifier.RSUS_STRING);
if (rsusIn.has(TimTransmogrifier.RSUS_STRING)) {
Object rsu = rsusIn.get(TimTransmogrifier.RSUS_STRING);
JSONArray rsusOut = new JSONArray();
if (rsu instanceof JSONArray) {
log.debug("Multiple RSUs exist in the request: {}", request);
JSONArray rsusInArray = (JSONArray) rsu;
for (int i = 0; i < rsusInArray.length(); i++) {
rsusOut.put(rsusInArray.get(i));
}
request.put(TimTransmogrifier.RSUS_STRING, rsusOut);
} else if (rsu instanceof JSONObject) {
log.debug("Single RSU exists in the request: {}", request);
rsusOut.put(rsu);
request.put(TimTransmogrifier.RSUS_STRING, rsusOut);
} else {
log.debug("No RSUs exist in the request: {}", request);
request.remove(TimTransmogrifier.RSUS_STRING);
}
}
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: as far as I can tell by reading the code and stepping through it with a debugger, this code block did nothing. The request variable is manipulated but never used after line 153. Please take a second look at this change. I'm fairly certain it can be safely deleted, but I may be missing something

+ consumedData;
if (log.isDebugEnabled()) {
// print error message and stack trace
EventLogger.logger.error(msg, e);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Does anyone know if there was a purpose to the EventLogger? Do we consume data from this logger differently?

Date requiredExpirationDate = new Date();
requiredExpirationDate.setTime(timTimestamp.getTime() + maxDurationTime);
timWithExpiration.put("requiredExpirationDate", dateFormat.format(requiredExpirationDate));
} catch (Exception e) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this is one of the rare times in this code where we can safely continue (as far as I can tell from the code) processing a message should an Exception be thrown. I intentionally handled the expectation here and allowed the processing to continue. I couldn't find any downstream issues in the code. Also, please note that we already handled the exception and continued processing in the previous implementation. This does not change the code flow.

Comment on lines +379 to +382
} catch (Exception e) {
log.error("Unable to get expiration date from signed messages response. Setting expirationData to 'null'", e);
timWithExpiration.put("expirationDate", "null");
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this is one of the rare times in this code where we can safely continue (as far as I can tell from the code) processing a message should an Exception be thrown. I intentionally handled the expectation here and allowed the processing to continue. I couldn't find any downstream issues in the code. Also, please note that we already handled the exception and continued processing in the previous implementation. This does not change the code flow.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This code is heavily tested indirectly by the Asn1EncodedDataRouter tests. The existing tests were not adding much value (I wrote most of them, so my bad), and meaningful tests were difficult to write without duplicating much of the testing already performed in the Asn1EncodedDataRouter tests.

…for Kafka container setup

Replaced ConcurrentMessageListenerContainer with KafkaMessageListenerContainer and removed KafkaConsumerConfig dependency. This fixes an issue where we would intermittently encounter the following error when running tests:

java.lang.IllegalStateException: Expected 1 but got 0 partitions
	at org.springframework.kafka.test.utils.ContainerTestUtils.waitForAssignment(ContainerTestUtils.java:85)
Updated the expiration date calculation to use `Instant` and ensure accuracy by handling milliseconds properly. Adjusted test cases and mock classes to align with the updated logic. Fixed incorrect test data to reflect the corrected expiration date format.
Replaced the outdated `SimpleDateFormat` with the modern `DateTimeFormatter` to handle date formatting and parsing. This improves thread safety and code readability while ensuring alignment with Java's modern date/time APIs. Adjusted test resources to reflect updated timestamp formatting logic.
Add exception handling to catch RestClientException when signing TIM messages. Log detailed error messages, including specific handling for HttpClientErrorException.NotFound, to provide better debugging information and highlight potential misconfiguration of jpo-security-svcs.
Convert TIM start flag to uppercase for consistency and improve logging to dynamically include the expected start flag value. This enhances clarity and ensures robust matching during header stripping.
Consolidated signing logic into `depositToTimCertExpirationTopic` and removed redundant `signTimWithExpiration` method. Added utility for obtaining hex-encoded signed messages in `SignatureResultModel` to streamline encoding operations.
If we fail to sign the message, we should fail to process the message further. We don't want any unsigned messages in our system (if signing is enabled)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant