Created
February 11, 2019 19:56
-
-
Save alopresto/a8af4cd4f6b37df55e4ab004428fb83a to your computer and use it in GitHub Desktop.
Very simplistic magnetic stripe track 1 & 2 parsing logic in Groovy. Extracts example fields and writes to JSON output.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import groovy.json.JsonBuilder | |
import groovy.json.JsonOutput | |
import groovy.json.JsonSlurper | |
import org.apache.commons.io.IOUtils | |
import org.apache.nifi.processor.io.StreamCallback | |
import java.nio.charset.StandardCharsets | |
def flowFile = session.get() | |
if (flowFile == null) { | |
return | |
} | |
final String CC_PATTERN = /^%B\d{16}\^[A-Za-z]+/ | |
final String PC_PATTERN = /^%1\w+/ | |
final String PP_PATTERN = /^%PP\/\/\w+/ | |
final String SBUX_PATTERN = /^%B601.*SERVICERECOVERY/ | |
String determinedType = "unknown" | |
flowFile = session.write(flowFile, { inputStream, outputStream -> | |
def content = IOUtils.toString(inputStream, StandardCharsets.UTF_8) | |
Map parsedObject | |
// Logic to do various parsing | |
if (content =~ CC_PATTERN) { | |
log.info("Detected CC format") | |
parsedObject = parse(content, "CC") | |
} else if (content =~ PP_PATTERN) { | |
log.info("Detected Priority Pass format") | |
parsedObject = parse(content, "PP") | |
} else if (content =~ PC_PATTERN) { | |
log.info("Detected Players Club format") | |
parsedObject = parse(content, "PC") | |
} else if (content =~ SBUX_PATTERN) { | |
log.info("Detected Starbucks Gift Card format") | |
parsedObject = parse(content, "SB") | |
} else { | |
log.info("Could not determine MSR type; using generic parsing heuristics") | |
parsedObject = parse(content, "generic") | |
} | |
// Write the determined type to an attribute | |
determinedType = parsedObject["type"] | |
// Write the timing info to the parsed object | |
parsedObject["time_parsed"] = new Date().format('YYYY-MM-dd_HH-mm-ss.SSS Z') | |
parsedObject["id"] = flowFile.uuid | |
parsedObject["source"] = flowFile.filename | |
// Convert the object into JSON | |
def jsonString = JsonOutput.toJson(parsedObject) | |
log.info("Formed JSON: ${jsonString}") | |
outputStream.write(jsonString.getBytes(StandardCharsets.UTF_8)) | |
} as StreamCallback) | |
flowFile.determinedType = determinedType | |
private Map parse(String content, String detectedType) { | |
Map parsedObject = [:] | |
parsedObject["type"] = detectedType | |
def tracks = content.split(/\?\n;/) | |
log.info("Tracks (${tracks.size()}): ${tracks.collect { "\n\t${it}" }}") | |
// Put the track 1 data directly | |
parsedObject["track1"] = tracks[0] | |
def track1Elements = tracks[0].split(/\^/) | |
log.info("Track 1 Elements (${track1Elements.size()}): ${track1Elements.collect { "\n\t${it}" }}") | |
// The PAN and Name are common elements | |
parsedObject["pan"] = track1Elements[0][2..-1] // Skip the start sentinel and format code (%B) | |
if (track1Elements.size() > 1) { | |
parsedObject["name"] = track1Elements[1].trim() | |
} | |
if (track1Elements.size() > 2) { | |
// Put the remaining track 1 data in a generic field | |
parsedObject["additionalTrack1"] = track1Elements[2..-1].join("^") | |
} | |
// Put track 2 data directly | |
parsedObject["track2"] = tracks[1] | |
// Return the parsed object | |
parsedObject | |
} | |
session.transfer(flowFile, REL_SUCCESS) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment