package com.cxd.Patient.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.stereotype.Repository;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
/**
* All resource providers must implement IResourceProvider
*/
@Repository
public class RestfulPatientResourceProvider implements IResourceProvider {
private FhirContext fhirContext;
private MongoOperations mongoOperations;
public RestfulPatientResourceProvider() {
}
public FhirContext getFhirContext() {
return fhirContext;
}
public void setFhirContext(FhirContext fhirContext) {
this.fhirContext = fhirContext;
}
public MongoOperations getMongoOperations() {
return mongoOperations;
}
public void setMongoOperations(MongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
/**
* The getResourceType method comes from IResourceProvider, and must be
* overridden to indicate what type of resource this provider supplies.
*/
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
/**
* This is the "read" operation. The "@Read" annotation indicates that this
* method supports the read and/or vread operation.
* <p>
* Read operations take a single parameter annotated with the
* {@link IdParam} paramater, and should return a single resource instance.
* </p>
*
* @param theId
* The read operation takes one parameter, which must be of type
* IdDt and must be annotated with the "@Read.IdParam"
* annotation.
* @return Returns a resource matching this identifier, or null if none
* exists.
*/
@Read(version = true)
public Patient readPatient(@IdParam IdDt theId) {
System.out.println("Id parameter:" + theId.getIdPart());
Patient patient = mongoOperations.findById(theId.getIdPart(),
Patient.class, "patient");
String jsonEncoded = fhirContext.newJsonParser().setPrettyPrint(true)
.encodeResourceToString(patient);
System.out.println(jsonEncoded);
return patient;
}
/**
* The "@Create" annotation indicates that this method implements
* "create=type", which adds a new instance of a resource to the server.
*/
@Create
public MethodOutcome createPatient(@ResourceParam Patient thePatient)
throws Exception {
UUID uid = UUID.randomUUID();
String idPart = new IdDt(uid.toString()).getValue();
thePatient.getIdentifier().get(0)
.setSystem(new UriDt("urn:cxdtest:mrns"));
thePatient.getIdentifier().get(0)
.setValue(thePatient.getIdentifierFirstRep().getValue());
validateResource(thePatient);
String jsonEncoded = fhirContext.newJsonParser().setPrettyPrint(true)
.encodeResourceToString(thePatient);
System.out.println(jsonEncoded);
try {
mongoOperations.insert(jsonEncoded, "patient");
} catch (Exception e) {
throw new Exception(e.getMessage());
}
return new MethodOutcome(thePatient.getId());
}
/**
* The "@Search" annotation indicates that this method supports the search
* operation. You may have many different method annotated with this
* annotation, to support many different search criteria. This example
* searches by family name.
*
* @param theFamilyName
* This operation takes one parameter which is the search
* criteria. It is annotated with the "@Required" annotation.
* This annotation takes one argument, a string containing the
* name of the search criteria. The datatype here is StringDt,
* but there are other possible parameter types depending on the
* specific search criteria.
* @return This method returns a list of Patients. This list may contain
* multiple matching resources, or it may also be empty.
*/
@Search()
public List<Patient> findPatientsByName(
@RequiredParam(name = Patient.SP_FAMILY) StringDt theFamilyName) {
List<Patient> patients = new ArrayList<Patient>();
/*
* Look for all patients matching the family name
*/
patients = mongoOperations.findAll(Patient.class, "patient");
for (Patient patient : patients)
{
NAMELOOP: for (HumanNameDt nextName : patient.getName()) {
for (StringDt nextFamily : nextName.getFamily()) {
if (theFamilyName.equals(nextFamily)) {
patients.add(patient);
break NAMELOOP;
}
}
}
}
return patients;
}
/**
* This method just provides simple business validation for resources we are
* storing.
*
* @param thePatient
* The patient to validate
*/
private void validateResource(Patient thePatient) {
/*
* Our server will have a rule that patients must have a family name or
* we will reject them
*/
if (thePatient.getNameFirstRep().getFamilyFirstRep().isEmpty()) {
OperationOutcome outcome = new OperationOutcome();
outcome.addIssue()
.setSeverity(IssueSeverityEnum.FATAL)
.setDetails(
"No family name provided, Patient resources must have at least one family name.");
throw new UnprocessableEntityException(outcome);
}
}
}
This is what I have right now. Obviously the Create API works but not the Search or Read operations.