Real-World Implementation Examples

Section 17 of 18
94% complete

Complete Patient Management System

A comprehensive example demonstrating real-world FHIR patterns. This implementation showcases production-ready patterns including patient registration, vital signs recording, and comprehensive record retrieval. The code demonstrates proper use of transaction bundles, the $everything operation, and LOINC-coded observations following clinical best practices.

import java.util.*;
import java.util.stream.Collectors;

public class PatientManagementSystem {

    private final IGenericClient client;
    private final FhirContext ctx;

    public PatientManagementSystem(String serverBase) {
        this.ctx = FhirContext.forR4();
        this.client = ctx.newRestfulGenericClient(serverBase);
    }

    // Register new patient
    public String registerPatient(PatientRegistrationRequest request) {
        Patient patient = new Patient();

        // Set identifiers
        patient.addIdentifier()
            .setSystem("http://hospital.org/mrn")
            .setValue(generateMRN())
            .setUse(Identifier.IdentifierUse.OFFICIAL);

        if (request.getSsn() != null) {
            patient.addIdentifier()
                .setSystem("http://hl7.org/fhir/sid/us-ssn")
                .setValue(request.getSsn());
        }

        // Set demographics
        patient.addName()
            .setFamily(request.getLastName())
            .addGiven(request.getFirstName())
            .addGiven(request.getMiddleName())
            .setUse(HumanName.NameUse.OFFICIAL);

        patient.setGender(request.getGender());
        patient.setBirthDate(request.getBirthDate());

        // Set contact information
        if (request.getPhone() != null) {
            patient.addTelecom()
                .setSystem(ContactPoint.ContactPointSystem.PHONE)
                .setValue(request.getPhone())
                .setUse(ContactPoint.ContactPointUse.MOBILE);
        }

        if (request.getEmail() != null) {
            patient.addTelecom()
                .setSystem(ContactPoint.ContactPointSystem.EMAIL)
                .setValue(request.getEmail());
        }

        // Set address
        if (request.getAddress() != null) {
            patient.addAddress()
                .setUse(Address.AddressUse.HOME)
                .addLine(request.getAddress().getStreet())
                .setCity(request.getAddress().getCity())
                .setState(request.getAddress().getState())
                .setPostalCode(request.getAddress().getZipCode())
                .setCountry("USA");
        }

        // Set marital status
        if (request.getMaritalStatus() != null) {
            patient.setMaritalStatus(new CodeableConcept()
                .addCoding()
                .setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus")
                .setCode(request.getMaritalStatus()));
        }

        // Add emergency contact
        if (request.getEmergencyContact() != null) {
            Patient.ContactComponent contact = patient.addContact();
            contact.addRelationship()
                .addCoding()
                .setSystem("http://terminology.hl7.org/CodeSystem/v2-0131")
                .setCode("C")
                .setDisplay("Emergency Contact");

            contact.setName(new HumanName()
                .setText(request.getEmergencyContact().getName()));

            contact.addTelecom()
                .setSystem(ContactPoint.ContactPointSystem.PHONE)
                .setValue(request.getEmergencyContact().getPhone());
        }

        patient.setActive(true);

        // Create patient
        MethodOutcome outcome = client.create()
            .resource(patient)
            .execute();

        return outcome.getId().getIdPart();
    }

    // Get comprehensive patient record
    public PatientRecord getPatientRecord(String patientId) {
        // Use $everything operation
        Bundle everything = client.operation()
            .onInstance(new IdType("Patient", patientId))
            .named("$everything")
            .withNoParameters(Parameters.class)
            .returnResourceType(Bundle.class)
            .execute();

        PatientRecord record = new PatientRecord();

        for (Bundle.BundleEntryComponent entry : everything.getEntry()) {
            Resource resource = entry.getResource();

            if (resource instanceof Patient) {
                record.setPatient((Patient) resource);
            } else if (resource instanceof Condition) {
                record.addCondition((Condition) resource);
            } else if (resource instanceof Observation) {
                record.addObservation((Observation) resource);
            } else if (resource instanceof MedicationRequest) {
                record.addMedication((MedicationRequest) resource);
            } else if (resource instanceof AllergyIntolerance) {
                record.addAllergy((AllergyIntolerance) resource);
            } else if (resource instanceof Procedure) {
                record.addProcedure((Procedure) resource);
            } else if (resource instanceof Encounter) {
                record.addEncounter((Encounter) resource);
            }
        }

        return record;
    }

    // Record vital signs
    public void recordVitalSigns(String patientId, VitalSignsData vitals) {
        Bundle bundle = new Bundle();
        bundle.setType(Bundle.BundleType.TRANSACTION);

        Date effectiveTime = new Date();
        String encounterId = vitals.getEncounterId();

        // Blood Pressure
        if (vitals.getSystolic() != null && vitals.getDiastolic() != null) {
            Observation bp = createBloodPressureObservation(
                patientId, vitals.getSystolic(), vitals.getDiastolic(),
                effectiveTime, encounterId);

            bundle.addEntry()
                .setResource(bp)
                .getRequest()
                    .setMethod(Bundle.HTTPVerb.POST)
                    .setUrl("Observation");
        }

        // Heart Rate
        if (vitals.getHeartRate() != null) {
            Observation hr = createSimpleObservation(
                patientId, "8867-4", "Heart rate",
                vitals.getHeartRate(), "beats/minute",
                effectiveTime, encounterId);

            bundle.addEntry()
                .setResource(hr)
                .getRequest()
                    .setMethod(Bundle.HTTPVerb.POST)
                    .setUrl("Observation");
        }

        // Temperature
        if (vitals.getTemperature() != null) {
            Observation temp = createSimpleObservation(
                patientId, "8310-5", "Body temperature",
                vitals.getTemperature(), "Cel",
                effectiveTime, encounterId);

            bundle.addEntry()
                .setResource(temp)
                .getRequest()
                    .setMethod(Bundle.HTTPVerb.POST)
                    .setUrl("Observation");
        }

        // Respiratory Rate
        if (vitals.getRespiratoryRate() != null) {
            Observation rr = createSimpleObservation(
                patientId, "9279-1", "Respiratory rate",
                vitals.getRespiratoryRate(), "breaths/minute",
                effectiveTime, encounterId);

            bundle.addEntry()
                .setResource(rr)
                .getRequest()
                    .setMethod(Bundle.HTTPVerb.POST)
                    .setUrl("Observation");
        }

        // Oxygen Saturation
        if (vitals.getOxygenSaturation() != null) {
            Observation spo2 = createSimpleObservation(
                patientId, "2708-6", "Oxygen saturation",
                vitals.getOxygenSaturation(), "%",
                effectiveTime, encounterId);

            bundle.addEntry()
                .setResource(spo2)
                .getRequest()
                    .setMethod(Bundle.HTTPVerb.POST)
                    .setUrl("Observation");
        }

        // Execute transaction
        client.transaction().withBundle(bundle).execute();
    }

    private Observation createBloodPressureObservation(
            String patientId, int systolic, int diastolic,
            Date effectiveTime, String encounterId) {

        Observation obs = new Observation();
        obs.setStatus(Observation.ObservationStatus.FINAL);

        obs.addCategory()
            .addCoding()
            .setSystem("http://terminology.hl7.org/CodeSystem/observation-category")
            .setCode("vital-signs");

        obs.setCode(new CodeableConcept()
            .addCoding()
            .setSystem("http://loinc.org")
            .setCode("85354-9")
            .setDisplay("Blood pressure panel"));

        obs.setSubject(new Reference("Patient/" + patientId));
        obs.setEffective(new DateTimeType(effectiveTime));

        if (encounterId != null) {
            obs.setEncounter(new Reference("Encounter/" + encounterId));
        }

        // Systolic component
        obs.addComponent()
            .setCode(new CodeableConcept()
                .addCoding()
                .setSystem("http://loinc.org")
                .setCode("8480-6")
                .setDisplay("Systolic blood pressure"))
            .setValue(new Quantity()
                .setValue(systolic)
                .setUnit("mmHg")
                .setSystem("http://unitsofmeasure.org")
                .setCode("mm[Hg]"));

        // Diastolic component
        obs.addComponent()
            .setCode(new CodeableConcept()
                .addCoding()
                .setSystem("http://loinc.org")
                .setCode("8462-4")
                .setDisplay("Diastolic blood pressure"))
            .setValue(new Quantity()
                .setValue(diastolic)
                .setUnit("mmHg")
                .setSystem("http://unitsofmeasure.org")
                .setCode("mm[Hg]"));

        return obs;
    }

    private Observation createSimpleObservation(
            String patientId, String loincCode, String display,
            Number value, String unit,
            Date effectiveTime, String encounterId) {

        Observation obs = new Observation();
        obs.setStatus(Observation.ObservationStatus.FINAL);

        obs.addCategory()
            .addCoding()
            .setSystem("http://terminology.hl7.org/CodeSystem/observation-category")
            .setCode("vital-signs");

        obs.setCode(new CodeableConcept()
            .addCoding()
            .setSystem("http://loinc.org")
            .setCode(loincCode)
            .setDisplay(display));

        obs.setSubject(new Reference("Patient/" + patientId));
        obs.setEffective(new DateTimeType(effectiveTime));

        if (encounterId != null) {
            obs.setEncounter(new Reference("Encounter/" + encounterId));
        }

        obs.setValue(new Quantity()
            .setValue(value.doubleValue())
            .setUnit(unit)
            .setSystem("http://unitsofmeasure.org"));

        return obs;
    }

    // Search patients
    public List<PatientSummary> searchPatients(PatientSearchCriteria criteria) {
        IQuery<Bundle> query = client.search().forResource(Patient.class);

        if (criteria.getLastName() != null) {
            query = query.where(Patient.FAMILY.matches().value(criteria.getLastName()));
        }

        if (criteria.getFirstName() != null) {
            query = query.where(Patient.GIVEN.matches().value(criteria.getFirstName()));
        }

        if (criteria.getBirthDate() != null) {
            query = query.where(Patient.BIRTHDATE.exactly().day(criteria.getBirthDate()));
        }

        if (criteria.getGender() != null) {
            query = query.where(Patient.GENDER.exactly().code(criteria.getGender().toCode()));
        }

        if (criteria.getIdentifier() != null) {
            query = query.where(Patient.IDENTIFIER.exactly()
                .identifier(criteria.getIdentifier()));
        }

        Bundle results = query
            .count(20)
            .returnBundle(Bundle.class)
            .execute();

        return results.getEntry().stream()
            .map(entry -> {
                Patient patient = (Patient) entry.getResource();
                return new PatientSummary(patient);
            })
            .collect(Collectors.toList());
    }

    private String generateMRN() {
        return "MRN-" + System.currentTimeMillis();
    }

    // Supporting classes
    public static class PatientRegistrationRequest {
        private String firstName;
        private String middleName;
        private String lastName;
        private String ssn;
        private Enumerations.AdministrativeGender gender;
        private Date birthDate;
        private String phone;
        private String email;
        private AddressInfo address;
        private String maritalStatus;
        private EmergencyContactInfo emergencyContact;

        // Getters and setters
        public String getFirstName() { return firstName; }
        public void setFirstName(String firstName) { this.firstName = firstName; }
        public String getMiddleName() { return middleName; }
        public void setMiddleName(String middleName) { this.middleName = middleName; }
        public String getLastName() { return lastName; }
        public void setLastName(String lastName) { this.lastName = lastName; }
        public String getSsn() { return ssn; }
        public void setSsn(String ssn) { this.ssn = ssn; }
        public Enumerations.AdministrativeGender getGender() { return gender; }
        public void setGender(Enumerations.AdministrativeGender gender) { this.gender = gender; }
        public Date getBirthDate() { return birthDate; }
        public void setBirthDate(Date birthDate) { this.birthDate = birthDate; }
        public String getPhone() { return phone; }
        public void setPhone(String phone) { this.phone = phone; }
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        public AddressInfo getAddress() { return address; }
        public void setAddress(AddressInfo address) { this.address = address; }
        public String getMaritalStatus() { return maritalStatus; }
        public void setMaritalStatus(String maritalStatus) { this.maritalStatus = maritalStatus; }
        public EmergencyContactInfo getEmergencyContact() { return emergencyContact; }
        public void setEmergencyContact(EmergencyContactInfo ec) { this.emergencyContact = ec; }
    }

    public static class AddressInfo {
        private String street;
        private String city;
        private String state;
        private String zipCode;

        public String getStreet() { return street; }
        public void setStreet(String street) { this.street = street; }
        public String getCity() { return city; }
        public void setCity(String city) { this.city = city; }
        public String getState() { return state; }
        public void setState(String state) { this.state = state; }
        public String getZipCode() { return zipCode; }
        public void setZipCode(String zipCode) { this.zipCode = zipCode; }
    }

    public static class EmergencyContactInfo {
        private String name;
        private String phone;

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getPhone() { return phone; }
        public void setPhone(String phone) { this.phone = phone; }
    }

    public static class VitalSignsData {
        private Integer systolic;
        private Integer diastolic;
        private Integer heartRate;
        private Double temperature;
        private Integer respiratoryRate;
        private Integer oxygenSaturation;
        private String encounterId;

        public Integer getSystolic() { return systolic; }
        public void setSystolic(Integer systolic) { this.systolic = systolic; }
        public Integer getDiastolic() { return diastolic; }
        public void setDiastolic(Integer diastolic) { this.diastolic = diastolic; }
        public Integer getHeartRate() { return heartRate; }
        public void setHeartRate(Integer heartRate) { this.heartRate = heartRate; }
        public Double getTemperature() { return temperature; }
        public void setTemperature(Double temperature) { this.temperature = temperature; }
        public Integer getRespiratoryRate() { return respiratoryRate; }
        public void setRespiratoryRate(Integer rr) { this.respiratoryRate = rr; }
        public Integer getOxygenSaturation() { return oxygenSaturation; }
        public void setOxygenSaturation(Integer spo2) { this.oxygenSaturation = spo2; }
        public String getEncounterId() { return encounterId; }
        public void setEncounterId(String encounterId) { this.encounterId = encounterId; }
    }

    public static class PatientRecord {
        private Patient patient;
        private List<Condition> conditions = new ArrayList<>();
        private List<Observation> observations = new ArrayList<>();
        private List<MedicationRequest> medications = new ArrayList<>();
        private List<AllergyIntolerance> allergies = new ArrayList<>();
        private List<Procedure> procedures = new ArrayList<>();
        private List<Encounter> encounters = new ArrayList<>();

        public Patient getPatient() { return patient; }
        public void setPatient(Patient patient) { this.patient = patient; }
        public List<Condition> getConditions() { return conditions; }
        public List<Observation> getObservations() { return observations; }
        public List<MedicationRequest> getMedications() { return medications; }
        public List<AllergyIntolerance> getAllergies() { return allergies; }
        public List<Procedure> getProcedures() { return procedures; }
        public List<Encounter> getEncounters() { return encounters; }

        public void addCondition(Condition c) { conditions.add(c); }
        public void addObservation(Observation o) { observations.add(o); }
        public void addMedication(MedicationRequest m) { medications.add(m); }
        public void addAllergy(AllergyIntolerance a) { allergies.add(a); }
        public void addProcedure(Procedure p) { procedures.add(p); }
        public void addEncounter(Encounter e) { encounters.add(e); }
    }

    public static class PatientSearchCriteria {
        private String lastName;
        private String firstName;
        private Date birthDate;
        private Enumerations.AdministrativeGender gender;
        private String identifier;

        public String getLastName() { return lastName; }
        public void setLastName(String lastName) { this.lastName = lastName; }
        public String getFirstName() { return firstName; }
        public void setFirstName(String firstName) { this.firstName = firstName; }
        public Date getBirthDate() { return birthDate; }
        public void setBirthDate(Date birthDate) { this.birthDate = birthDate; }
        public Enumerations.AdministrativeGender getGender() { return gender; }
        public void setGender(Enumerations.AdministrativeGender gender) { this.gender = gender; }
        public String getIdentifier() { return identifier; }
        public void setIdentifier(String identifier) { this.identifier = identifier; }
    }

    public static class PatientSummary {
        private String id;
        private String name;
        private Enumerations.AdministrativeGender gender;
        private Date birthDate;
        private String mrn;

        public PatientSummary(Patient patient) {
            this.id = patient.getIdElement().getIdPart();
            this.name = patient.getNameFirstRep().getNameAsSingleString();
            this.gender = patient.getGender();
            this.birthDate = patient.getBirthDate();

            patient.getIdentifier().stream()
                .filter(id -> id.getSystem() != null && id.getSystem().contains("mrn"))
                .findFirst()
                .ifPresent(id -> this.mrn = id.getValue());
        }

        public String getId() { return id; }
        public String getName() { return name; }
        public Enumerations.AdministrativeGender getGender() { return gender; }
        public Date getBirthDate() { return birthDate; }
        public String getMrn() { return mrn; }
    }
}

Common LOINC Codes for Vital Signs

Vital SignLOINC CodeDisplay
Blood Pressure Panel85354-9Blood pressure panel
Systolic BP8480-6Systolic blood pressure
Diastolic BP8462-4Diastolic blood pressure
Heart Rate8867-4Heart rate
Respiratory Rate9279-1Respiratory rate
Body Temperature8310-5Body temperature
Oxygen Saturation2708-6Oxygen saturation
Body Weight29463-7Body weight
Body Height8302-2Body height
BMI39156-5Body mass index

Quiz: Real-World Implementation Examples

Question 1 of 5

What operation retrieves a patient's complete medical record?