dpc-common/src/main/java/gov/cms/dpc/common/utils/SeedProcessor.java
package gov.cms.dpc.common.utils;
import gov.cms.dpc.fhir.DPCIdentifierSystem;
import gov.cms.dpc.fhir.FHIRBuilders;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.dstu3.model.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;
/**
* Utility class for process the test attribution file.
* Mostly used for testing, but also by the SeedCommand in the AttributionService
*/
public class SeedProcessor {
private static final SecureRandom rand = new SecureRandom();
private SeedProcessor() {
// Not used
}
/**
* Processes the provided attribution file and groups the patients by provider ID
*
* @param stream - {@link InputStream} of associations file to load
* @return - {@link Map} of Provider IDs and a {@link List} of {@link Pair} of providerID and patientID
* @throws IOException - throws if unable to read the input file
*/
public static Map<String, List<Pair<String, String>>> extractProviderMap(InputStream stream) throws IOException {
List<Pair<String, String>> providerPairs = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
for (String line; (line = reader.readLine()) != null; ) {
// We can ignore this, because it's not worth pulling in Guava just for this.
final String[] splits = line.split(",", -1);
providerPairs.add(Pair.of(splits[1], splits[0]));
}
}
return providerPairs
.stream()
.collect(Collectors.groupingBy(Pair::getLeft));
}
/**
* Creates a FHIR {@link Bundle} for the given {@link Map} entry, generated by the {@link SeedProcessor#extractProviderMap(InputStream)} function.
* * For the {@link Bundle}, the first entry is the {@link Practitioner} resource, and all subsequent entries are {@link Patient} resources
*
* @param entry - {@link Map#entry(Object, Object)} representing the providerID and a {@link List} of {@link Pair} objects containing both the providerID and the patientID
* @param organizationID - {@link UUID} of organization to register attribution group to
* @param patientReferences - {@link Map} patient ID lookup map
* @return - {@link Group} which attributes to the given {@link Patient} entities to the {@link Practitioner} entity.
*/
public static Group generateAttributionGroup(Map.Entry<String, List<Pair<String, String>>> entry, UUID organizationID, Map<String, Reference> patientReferences) {
final Group group = createBaseAttributionGroup(entry.getKey(), organizationID.toString());
final List<Group.GroupMemberComponent> members = entry
.getValue()
.stream()
.map(Pair::getRight)
.map(patientReferences::get)
.filter(Objects::nonNull)
.map(ref -> {
final Group.GroupMemberComponent member = new Group.GroupMemberComponent();
member
.setInactive(false)
.setEntity(ref);
return member;
})
.collect(Collectors.toList());
return group.setMember(members);
}
public static Bundle generateAttributionBundle(Map.Entry<String, List<Pair<String, String>>> entry, UUID organizationID) {
final Bundle bundle = new Bundle();
bundle.setId(new IdType("Roster", "12345"));
bundle.setType(Bundle.BundleType.COLLECTION);
// Create the provider with the necessary fields
final Practitioner practitioner = new Practitioner();
practitioner.addIdentifier().setValue(entry.getKey()).setSystem(DPCIdentifierSystem.NPPES.getSystem());
practitioner.addName().addGiven("Test").setFamily("Provider");
// Add the Organization ID
FHIRBuilders.addOrganizationTag(practitioner, organizationID);
bundle.addEntry().setResource(practitioner).setFullUrl("http://something.gov/" + practitioner.getIdentifierFirstRep().getValue());
entry.getValue()
.forEach((value) -> {
// Add some random values to the patient
final Patient patient = new Patient();
patient.addIdentifier().setValue(value.getRight()).setSystem(DPCIdentifierSystem.MBI.getSystem());
patient.addName().addGiven("Tester " + rand.nextInt()).setFamily("Patient");
patient.setBirthDate(new GregorianCalendar(2019, Calendar.MARCH, 1).getTime());
patient.setManagingOrganization(new Reference(new IdType("Organization", organizationID.toString())));
patient.setGender(Enumerations.AdministrativeGender.UNKNOWN);
final Bundle.BundleEntryComponent component = new Bundle.BundleEntryComponent();
component.setResource(patient);
component.setFullUrl("http://something.gov/" + patient.getIdentifierFirstRep().getValue());
bundle.addEntry(component);
});
return bundle;
}
public static Group createBaseAttributionGroup(String providerNPI, String organizationID) {
final CodeableConcept attributionConcept = new CodeableConcept();
attributionConcept.addCoding().setCode("attributed-to");
final CodeableConcept NPIConcept = new CodeableConcept();
NPIConcept.addCoding().setSystem(DPCIdentifierSystem.NPPES.getSystem()).setCode(providerNPI);
final Group rosterGroup = new Group();
rosterGroup.setType(Group.GroupType.PERSON);
rosterGroup.setActive(true);
rosterGroup.addCharacteristic()
.setExclude(false)
.setCode(attributionConcept)
.setValue(NPIConcept);
FHIRBuilders.addOrganizationTag(rosterGroup, UUID.fromString(organizationID));
return rosterGroup;
}
}