Skip to content

Commit

Permalink
Ab2d-5997/conf reason code upd (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
smirnovaae authored Mar 11, 2024
1 parent 7e92fa0 commit 744556e
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 250 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ private AttributionDataShareConstants() {
public static final String TEST_ENDPOINT = "http://127.0.0.1:8001";
public static final Region S3_REGION = Region.US_EAST_1;
public static final String FILE_PATH = "/tmp/";
public static final String FILE_PARTIAL_NAME = "ab2d-beneids_";
public static final String FILE_FORMAT = ".txt";
public static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
public static final String REQ_FILE_NAME = "P.AB2D.NGD.REQ.";
public static final String REQ_FILE_NAME_PATTERN = "'D'yyMMdd.'T'hhmmsss";
public static final String REQ_FILE_FORMAT = ".OUT";

public static final String FIRST_LINE = "HDR_BENEDATAREQ_";
public static final String LAST_LINE = "TLR_BENEDATAREQ_";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@
public class AttributionDataShareHandler implements RequestStreamHandler {

// Writes out a file to the FILE_PATH.
// I.E: "ab2d-beneids_2023-08-16T12:08:56.235-0700.txt"
// I.E: "P.AB2D.NGD.REQ.D240209.T1122001.OUT"

public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
LambdaLogger logger = context.getLogger();
logger.log("AttributionDataShare Lambda is started");

String currentDate = new SimpleDateFormat(PATTERN).format(new Date());
String fileName = FILE_PARTIAL_NAME + currentDate + FILE_FORMAT;
String currentDate = new SimpleDateFormat(REQ_FILE_NAME_PATTERN).format(new Date());
String fileName = REQ_FILE_NAME + currentDate + REQ_FILE_FORMAT;
String fileFullPath = FILE_PATH + fileName;
AttributionDataShareHelper helper = helperInit(fileName, fileFullPath, logger);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class AttributionDataShareTest {
private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = new AB2DPostgresqlContainer();
LambdaLogger LOGGER = mock(LambdaLogger.class);

String FILE_NAME = FILE_PARTIAL_NAME + new SimpleDateFormat(PATTERN).format(new Date()) + FILE_FORMAT;
String FILE_NAME = REQ_FILE_NAME + new SimpleDateFormat(REQ_FILE_NAME_PATTERN).format(new Date()) + REQ_FILE_FORMAT;
String FILE_FULL_PATH = FILE_PATH + FILE_NAME;

String MBI = "DUMMY000001";
Expand Down
23 changes: 11 additions & 12 deletions optout/src/main/java/gov/cms/ab2d/optout/OptOutConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,24 @@ public class OptOutConstants {
public static final String TEST_FILE_NAME = "optOutDummy.txt";
public static final String BFD_S3_BUCKET_NAME = "ab2d-opt-out-temp-349849222861-us-east-1";
public static final Region S3_REGION = Region.US_EAST_1;
public static final String FIRST_LINE = "HDR_BENEDATASHR";
public static final String LAST_LINE = "TRL_BENEDATASHR";
public static final int DEFAULT_LINE_LENGTH = 459;
public static final String HEADER_RESP = "HDR_BENEDATARSP";
public static final String TRAILER_RESP = "TLR_BENEDATARSP";
public static final String AB2D_HEADER_CONF = "HDR_BENECONFIRM";
public static final String AB2D_TRAILER_CONF = "TLR_BENECONFIRM";
public static final int MBI_INDEX_START = 0;
public static final int MBI_INDEX_END = 11;
public static final int EFFECTIVE_DATE_INDEX_START = 354;
public static final int EFFECTIVE_DATE_INDEX_END = 362;
public static final int OPTOUT_FLAG_INDEX = 368;
public static final String RECORD_STATUS_PATTERN = "%-10s";
public static final int OPTOUT_FLAG_INDEX = 11;
public static final String EFFECTIVE_DATE_PATTERN = "yyyyMMdd";
public static final int EFFECTIVE_DATE_LENGTH = 8;
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final String RESPONSE_FILE_NAME = "P.AB2D.DPRF.RSP.";
public static final String RESPONSE_FILE_NAME_PATTERN = "'D'yyMMdd.'T'hhmmssss";

public static final String CONF_FILE_NAME = "P.AB2D.NGD.CONF.";
public static final String CONF_FILE_NAME_PATTERN = "'D'yyMMdd.'T'hhmmsss";
public static final String CONF_FILE_FORMAT = ".OUT";
public static final String UPDATE_STATEMENT = "UPDATE public.coverage\n" +
"SET opt_out_flag = ?, effective_date = ?\n" +
"SET opt_out_flag = ?, effective_date = current_timestamp\n" +
"WHERE current_mbi = ? OR historic_mbis LIKE CONCAT( '%',?,'%')";


private OptOutConstants() {
}
}
}
39 changes: 6 additions & 33 deletions optout/src/main/java/gov/cms/ab2d/optout/OptOutInformation.java
Original file line number Diff line number Diff line change
@@ -1,44 +1,17 @@
package gov.cms.ab2d.optout;

import java.sql.Timestamp;

public class OptOutInformation {
private final String text;
private String mbi;
private Timestamp effectiveDate;
private boolean optOutFlag;
private final long lineNumber;

public OptOutInformation(String mbi, Timestamp effectiveDate, boolean optOutFlag, long lineNumber, String text) {
private final String mbi;
private final Boolean optOutFlag;
public OptOutInformation(String mbi, Boolean optOutFlag) {
this.mbi = mbi;
this.effectiveDate = effectiveDate;
this.optOutFlag = optOutFlag;
this.lineNumber = lineNumber;
this.text = text;
}

public OptOutInformation(long lineNumber, String text) {
this.lineNumber = lineNumber;
this.text = text;
public Boolean getOptOutFlag() {
return optOutFlag;
}

public String getMbi() {
return mbi;
}

public Timestamp getEffectiveDate() {
return effectiveDate;
}

public boolean isOptOut() {
return optOutFlag;
}

public long getLineNumber() {
return lineNumber;
}

public String getText() {
return text;
}
}
}
110 changes: 46 additions & 64 deletions optout/src/main/java/gov/cms/ab2d/optout/OptOutProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,36 @@
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Optional;
import java.util.Date;
import java.util.SortedMap;
import java.util.TreeMap;

import static gov.cms.ab2d.optout.OptOutConstants.*;

public class OptOutProcessor {
private final LambdaLogger logger;
public SortedMap<Long, OptOutResult> optOutResultMap;
public SortedMap<Long, OptOutInformation> optOutInformationMap;
public boolean isRejected;
private final OptOutS3 optOutS3;

public OptOutProcessor(String fileName, String endpoint, LambdaLogger logger) throws URISyntaxException {
this.logger = logger;
this.optOutResultMap = new TreeMap<>();
this.optOutInformationMap = new TreeMap<>();
var s3Client = S3Client.builder()
// .credentialsProvider(credentials)
.region(S3_REGION)
.endpointOverride(new URI(endpoint))
.build();
isRejected = false;
optOutS3 = new OptOutS3(s3Client, fileName, logger);
}

public void process() {
processFileFromS3(optOutS3.openFileS3());
optOutS3.createResponseOptOutFile(createResponseContent());
if (!isRejected)
optOutS3.deleteFileFromS3();
}

public void processFileFromS3(BufferedReader reader) {
Expand All @@ -48,9 +50,11 @@ public void processFileFromS3(BufferedReader reader) {
var lineNumber = 0L;
try {
while ((line = reader.readLine()) != null) {
var optOutInformation = createOptOutInformation(line, lineNumber);
// If the file line was parsed successfully, update the optout values in the database
optOutInformation.ifPresent(information -> updateOptOut(information, dbConnection));
if (!line.startsWith(HEADER_RESP) && !line.startsWith(TRAILER_RESP)) {
var optOutInformation = createOptOutInformation(line);
optOutInformationMap.put(lineNumber, optOutInformation);
updateOptOut(lineNumber, optOutInformation, dbConnection);
}
lineNumber++;
}
} catch (IOException ex) {
Expand All @@ -59,80 +63,58 @@ public void processFileFromS3(BufferedReader reader) {
}
}

public Optional<OptOutInformation> createOptOutInformation(String information, long lineNumber) throws IllegalArgumentException {
try {
var mbi = information.substring(MBI_INDEX_START, MBI_INDEX_END).trim();
var effectiveDate = convertToDate(information.substring(EFFECTIVE_DATE_INDEX_START, EFFECTIVE_DATE_INDEX_END));
var optOutFlag = (information.charAt(OPTOUT_FLAG_INDEX) == 'Y');

var optOutInformation = new OptOutInformation(mbi, effectiveDate, optOutFlag, lineNumber, information);
// The file line was parsed successfully
optOutResultMap.put(lineNumber, new OptOutResult(optOutInformation, RecordStatus.ACCEPTED, ReasonCode.ACCEPTED));
return Optional.of(optOutInformation);
} catch (NumberFormatException | StringIndexOutOfBoundsException | ParseException ex) {
logger.log("Lambda can not parse the line: " + lineNumber);
// The file line was parsed with an error
optOutResultMap.put(lineNumber, new OptOutResult(new OptOutInformation(lineNumber, information), RecordStatus.REJECTED, ReasonCode.PARSE_ERROR));
if (!information.startsWith(FIRST_LINE) && !information.startsWith(LAST_LINE)) {
logger.log("There is a parsing error on the line " + lineNumber);
}
}
return Optional.empty();
public OptOutInformation createOptOutInformation(String information) {
var mbi = information.substring(MBI_INDEX_START, MBI_INDEX_END).trim();
var optOutFlag = (information.charAt(OPTOUT_FLAG_INDEX) == 'Y');
return new OptOutInformation(mbi, optOutFlag);
}

public void updateOptOut(OptOutInformation optOutInformation, Connection dbConnection) {
public void updateOptOut(long lineNumber, OptOutInformation optOutInformation, Connection dbConnection) {
try (var statement = dbConnection.prepareStatement(UPDATE_STATEMENT)) {
logger.log("Mbi: " + optOutInformation.getMbi() + ", OptOut Flag: " + optOutInformation.isOptOut());
prepareInsert(optOutInformation, statement);
statement.execute();
} catch (SQLException ex) {
optOutResultMap.put(optOutInformation.getLineNumber(),
new OptOutResult(
new OptOutInformation(optOutInformation.getLineNumber(), optOutInformation.getText()),
RecordStatus.REJECTED,
ReasonCode.INSERT_ERROR));
logger.log("There is an insertion error on the line " + optOutInformation.getLineNumber());
logger.log("There is an insertion error on the line " + lineNumber);
logger.log(ex.getMessage());
isRejected = true;
}
}

public String createResponseContent() {
var date = new SimpleDateFormat(EFFECTIVE_DATE_PATTERN).format(new Date());
var responseContent = new StringBuilder();
for (var optOutResult : optOutResultMap.entrySet()) {
var line = optOutResult.getValue();
var text = line.getOptOutInformation().getText();
// First and last lines don't contain optout data and are written as is
if (optOutResult.getKey() == 0 || optOutResult.getKey() == optOutResultMap.size() - 1) {
responseContent.append(text);
} else {
var result = new StringBuilder(text);
// Adding spaces to the end of a string to achieve the RecordStatus position index
if (text.length() < DEFAULT_LINE_LENGTH)
result.append(" ".repeat(Math.max(0, DEFAULT_LINE_LENGTH - text.length())));

result.append(String.format(RECORD_STATUS_PATTERN, line.getRecordStatus()));
result.append(line.getReasonCode());
responseContent.append(result);
}
responseContent.append(LINE_SEPARATOR);
responseContent.append(AB2D_HEADER_CONF).append(date);
responseContent.append(LINE_SEPARATOR);
var recordStatus = getRecordStatus();
var effectiveDate = getEffectiveDate(date);

for (var optOutResult : optOutInformationMap.entrySet()) {
var info = optOutResult.getValue();

responseContent.append(info.getMbi())
.append(effectiveDate)
.append((info.getOptOutFlag()) ? 'Y' : 'N')
.append(recordStatus)
.append(LINE_SEPARATOR);
}
// Remove last empty line
responseContent.delete(responseContent.lastIndexOf(LINE_SEPARATOR), responseContent.length());
responseContent.append(AB2D_TRAILER_CONF).append(date).append(String.format("%010d", optOutInformationMap.size()));

return responseContent.toString();
}

public String getRecordStatus() {
return (isRejected) ? RecordStatus.REJECTED.toString() : RecordStatus.ACCEPTED.toString();
}

public String getEffectiveDate(String date){
return (isRejected) ? " ".repeat(EFFECTIVE_DATE_LENGTH) : date;
}

private static void prepareInsert(OptOutInformation optOut, PreparedStatement statement) throws SQLException {
statement.setBoolean(1, optOut.isOptOut());
statement.setTimestamp(2, optOut.getEffectiveDate());
statement.setBoolean(1, optOut.getOptOutFlag());
statement.setString(2, optOut.getMbi());
statement.setString(3, optOut.getMbi());
statement.setString(4, optOut.getMbi());
statement.addBatch();
}

private Timestamp convertToDate(String date) throws ParseException {
var dateFormat = new SimpleDateFormat(EFFECTIVE_DATE_PATTERN);
var parsedDate = dateFormat.parse(date);
return new Timestamp(parsedDate.getTime());
}

}
}
26 changes: 0 additions & 26 deletions optout/src/main/java/gov/cms/ab2d/optout/OptOutResult.java

This file was deleted.

7 changes: 5 additions & 2 deletions optout/src/main/java/gov/cms/ab2d/optout/OptOutS3.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ public BufferedReader openFileS3() {

public String createResponseOptOutFile(String responseContent) {
try {
var key = RESPONSE_FILE_NAME + new SimpleDateFormat(RESPONSE_FILE_NAME_PATTERN).format(new Date());
var key = CONF_FILE_NAME
+ new SimpleDateFormat(CONF_FILE_NAME_PATTERN).format(new Date())
+ CONF_FILE_FORMAT;

var objectRequest = PutObjectRequest.builder()
.bucket(BFD_S3_BUCKET_NAME)
.key(key)
Expand Down Expand Up @@ -89,4 +92,4 @@ public void deleteFileFromS3() {
}


}
}
12 changes: 0 additions & 12 deletions optout/src/main/java/gov/cms/ab2d/optout/ReasonCode.java

This file was deleted.

14 changes: 10 additions & 4 deletions optout/src/main/java/gov/cms/ab2d/optout/RecordStatus.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package gov.cms.ab2d.optout;

public final class RecordStatus {

public static final String ACCEPTED = "Accepted";
public static final String REJECTED = "Rejected";
public enum RecordStatus {

private RecordStatus() {
ACCEPTED("Accepted 00"),
REJECTED("Rejected 02");
private final String status;
RecordStatus(final String status) {
this.status = status;
}
@Override
public String toString() {
return status;
}

}
Expand Down
Loading

0 comments on commit 744556e

Please sign in to comment.