1020 lines
33 KiB
Java
1020 lines
33 KiB
Java
package example;
|
|
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
import ca.uhn.fhir.context.FhirContext;
|
|
import ca.uhn.fhir.model.api.Bundle;
|
|
import ca.uhn.fhir.model.api.IResource;
|
|
import ca.uhn.fhir.model.api.Include;
|
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
|
import ca.uhn.fhir.model.api.Tag;
|
|
import ca.uhn.fhir.model.api.TagList;
|
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
|
import ca.uhn.fhir.model.api.annotation.Description;
|
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
|
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
|
|
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
|
|
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
|
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
|
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
|
|
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
|
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
|
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
|
import ca.uhn.fhir.model.primitive.DecimalDt;
|
|
import ca.uhn.fhir.model.primitive.IdDt;
|
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
|
import ca.uhn.fhir.parser.DataFormatException;
|
|
import ca.uhn.fhir.rest.annotation.AddTags;
|
|
import ca.uhn.fhir.rest.annotation.Count;
|
|
import ca.uhn.fhir.rest.annotation.Create;
|
|
import ca.uhn.fhir.rest.annotation.DeleteTags;
|
|
import ca.uhn.fhir.rest.annotation.GetTags;
|
|
import ca.uhn.fhir.rest.annotation.History;
|
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
|
import ca.uhn.fhir.rest.annotation.Metadata;
|
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
|
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.annotation.Since;
|
|
import ca.uhn.fhir.rest.annotation.Sort;
|
|
import ca.uhn.fhir.rest.annotation.TagListParam;
|
|
import ca.uhn.fhir.rest.annotation.Transaction;
|
|
import ca.uhn.fhir.rest.annotation.TransactionParam;
|
|
import ca.uhn.fhir.rest.annotation.Update;
|
|
import ca.uhn.fhir.rest.annotation.Validate;
|
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
|
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
|
import ca.uhn.fhir.rest.api.SortSpec;
|
|
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
|
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
|
import ca.uhn.fhir.rest.param.CompositeParam;
|
|
import ca.uhn.fhir.rest.param.DateParam;
|
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
|
import ca.uhn.fhir.rest.param.QuantityParam;
|
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
|
import ca.uhn.fhir.rest.param.StringAndListParam;
|
|
import ca.uhn.fhir.rest.param.StringOrListParam;
|
|
import ca.uhn.fhir.rest.param.StringParam;
|
|
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
|
import ca.uhn.fhir.rest.param.TokenParam;
|
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
|
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
|
|
|
@SuppressWarnings("unused")
|
|
public abstract class RestfulPatientResourceProviderMore implements IResourceProvider {
|
|
|
|
public interface ITestClient extends IBasicClient
|
|
{
|
|
|
|
@Search
|
|
List<Patient> getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theParam);
|
|
|
|
}
|
|
|
|
private boolean detectedVersionConflict;
|
|
private boolean conflictHappened;
|
|
private boolean couldntFindThisId;
|
|
//START SNIPPET: searchAll
|
|
@Search
|
|
public List<Organization> getAllOrganizations() {
|
|
List<Organization> retVal=new ArrayList<Organization>(); // populate this
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchAll
|
|
|
|
//START SNIPPET: searchCompartment
|
|
public class PatientRp implements IResourceProvider {
|
|
|
|
@Override
|
|
public Class<? extends IResource> getResourceType() {
|
|
return Patient.class;
|
|
}
|
|
|
|
@Search(compartmentName="Condition")
|
|
public List<IResource> searchCompartment(@IdParam IdDt thePatientId) {
|
|
List<IResource> retVal=new ArrayList<IResource>();
|
|
|
|
// populate this with resources of any type that are a part of the
|
|
// "Condition" compartment for the Patient with ID "thePatientId"
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// .. also include other Patient operations ..
|
|
}
|
|
//END SNIPPET: searchCompartment
|
|
|
|
|
|
//START SNIPPET: sort
|
|
@Search
|
|
public List<Patient> findPatients(
|
|
@RequiredParam(name=Patient.SP_IDENTIFIER) StringParam theParameter,
|
|
@Sort SortSpec theSort) {
|
|
List<Patient> retVal=new ArrayList<Patient>(); // populate this
|
|
|
|
// theSort is null unless a _sort parameter is actually provided
|
|
if (theSort != null) {
|
|
|
|
// The name of the param to sort by
|
|
String param = theSort.getParamName();
|
|
|
|
// The sort order, or null
|
|
SortOrderEnum order = theSort.getOrder();
|
|
|
|
// This will be populated if a second _sort was specified
|
|
SortSpec subSort = theSort.getChain();
|
|
|
|
// ...apply the sort...
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: sort
|
|
|
|
//START SNIPPET: underlyingReq
|
|
@Search
|
|
public List<Patient> findPatients(
|
|
@RequiredParam(name="foo") StringParam theParameter,
|
|
HttpServletRequest theRequest,
|
|
HttpServletResponse theResponse) {
|
|
List<Patient> retVal=new ArrayList<Patient>(); // populate this
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: underlyingReq
|
|
|
|
//START SNIPPET: referenceSimple
|
|
@Search
|
|
public List<Patient> findPatientsWithSimpleReference(
|
|
@OptionalParam(name=Patient.SP_CAREPROVIDER) ReferenceParam theProvider
|
|
) {
|
|
List<Patient> retVal=new ArrayList<Patient>();
|
|
|
|
// If the parameter passed in includes a resource type (e.g. ?provider:Patient=123)
|
|
// that resoruce type is available. Here we just check that it is either not provided
|
|
// or set to "Patient"
|
|
if (theProvider.hasResourceType()) {
|
|
String resourceType = theProvider.getResourceType();
|
|
if ("Patient".equals(resourceType) == false) {
|
|
throw new InvalidRequestException("Invalid resource type for parameter 'provider': " + resourceType);
|
|
}
|
|
}
|
|
|
|
if (theProvider != null) {
|
|
// ReferenceParam extends IdDt so all of the resource ID methods are available
|
|
String providerId = theProvider.getIdPart();
|
|
|
|
// .. populate retVal will Patient resources having provider with id "providerId" ..
|
|
|
|
}
|
|
|
|
return retVal;
|
|
|
|
}
|
|
//END SNIPPET: referenceSimple
|
|
|
|
|
|
//START SNIPPET: referenceWithChain
|
|
@Search
|
|
public List<DiagnosticReport> findReportsWithChain(
|
|
@RequiredParam(name=DiagnosticReport.SP_SUBJECT, chainWhitelist= {Patient.SP_FAMILY, Patient.SP_GENDER}) ReferenceParam theSubject
|
|
) {
|
|
List<DiagnosticReport> retVal=new ArrayList<DiagnosticReport>();
|
|
|
|
String chain = theSubject.getChain();
|
|
if (Patient.SP_FAMILY.equals(chain)) {
|
|
String familyName = theSubject.getValue();
|
|
// .. populate with reports matching subject family name ..
|
|
}
|
|
if (Patient.SP_GENDER.equals(chain)) {
|
|
String gender = theSubject.getValue();
|
|
// .. populate with reports matching subject gender ..
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: referenceWithChain
|
|
|
|
|
|
//START SNIPPET: referenceWithChainCombo
|
|
@Search
|
|
public List<DiagnosticReport> findReportsWithChainCombo (
|
|
@RequiredParam(name=DiagnosticReport.SP_SUBJECT, chainWhitelist= {"", Patient.SP_FAMILY}) ReferenceParam theSubject
|
|
) {
|
|
List<DiagnosticReport> retVal=new ArrayList<DiagnosticReport>();
|
|
|
|
String chain = theSubject.getChain();
|
|
if (Patient.SP_FAMILY.equals(chain)) {
|
|
String familyName = theSubject.getValue();
|
|
// .. populate with reports matching subject family name ..
|
|
}
|
|
if ("".equals(chain)) {
|
|
String resourceId = theSubject.getValue();
|
|
// .. populate with reports matching subject with resource ID ..
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: referenceWithChainCombo
|
|
|
|
|
|
//START SNIPPET: referenceWithStaticChain
|
|
@Search
|
|
public List<Patient> findObservations(
|
|
@RequiredParam(name=Observation.SP_SUBJECT+'.'+Patient.SP_IDENTIFIER) TokenParam theProvider
|
|
) {
|
|
|
|
String system = theProvider.getSystem();
|
|
String identifier = theProvider.getValue();
|
|
|
|
// ...Do a search for all observations for the given subject...
|
|
|
|
List<Patient> retVal=new ArrayList<Patient>(); // populate this
|
|
return retVal;
|
|
|
|
}
|
|
//END SNIPPET: referenceWithStaticChain
|
|
|
|
|
|
//START SNIPPET: referenceWithDynamicChain
|
|
@Search()
|
|
public List<Observation> findBySubject(
|
|
@RequiredParam(name=Observation.SP_SUBJECT, chainWhitelist = {"", Patient.SP_IDENTIFIER, Patient.SP_BIRTHDATE}) ReferenceParam subject
|
|
) {
|
|
List<Observation> observations = new ArrayList<Observation>();
|
|
|
|
String chain = subject.getChain();
|
|
if (Patient.SP_IDENTIFIER.equals(chain)) {
|
|
|
|
// Because the chained parameter "subject.identifier" is actually of type
|
|
// "token", we convert the value to a token before processing it.
|
|
TokenParam tokenSubject = subject.toTokenParam();
|
|
String system = tokenSubject.getSystem();
|
|
String identifier = tokenSubject.getValue();
|
|
|
|
// TODO: populate all the observations for the identifier
|
|
|
|
} else if (Patient.SP_BIRTHDATE.equals(chain)) {
|
|
|
|
// Because the chained parameter "subject.birthdate" is actually of type
|
|
// "date", we convert the value to a date before processing it.
|
|
DateParam dateSubject = subject.toDateParam();
|
|
DateTimeDt birthDate = dateSubject.getValueAsDateTimeDt();
|
|
|
|
// TODO: populate all the observations for the birthdate
|
|
|
|
} else if ("".equals(chain)) {
|
|
|
|
String resourceId = subject.getValue();
|
|
// TODO: populate all the observations for the resource id
|
|
|
|
}
|
|
|
|
return observations;
|
|
}
|
|
//END SNIPPET: referenceWithDynamicChain
|
|
|
|
|
|
//START SNIPPET: read
|
|
@Read()
|
|
public Patient getResourceById(@IdParam IdDt theId) {
|
|
Patient retVal = new Patient();
|
|
|
|
// ...populate...
|
|
retVal.addIdentifier().setSystem("urn:mrns").setValue("12345").setLabel("MRN 12345");
|
|
retVal.addName().addFamily("Smith").addGiven("Tester").addGiven("Q");
|
|
// ...etc...
|
|
|
|
// if you know the version ID of the resource, you should set it and HAPI will
|
|
// include it in a Content-Location header
|
|
retVal.setId(new IdDt("Patient", "123", "2"));
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: read
|
|
|
|
//START SNIPPET: delete
|
|
@Read()
|
|
public void deletePatient(@IdParam IdDt theId) {
|
|
// .. Delete the patient ..
|
|
if (couldntFindThisId) {
|
|
throw new ResourceNotFoundException("Unknown version");
|
|
}
|
|
if (conflictHappened) {
|
|
throw new ResourceVersionConflictException("Couldn't delete because [foo]");
|
|
}
|
|
// otherwise, delete was successful
|
|
return; // can also return MethodOutcome
|
|
}
|
|
//END SNIPPET: delete
|
|
|
|
|
|
//START SNIPPET: history
|
|
@History()
|
|
public List<Patient> getPatientHistory(@IdParam IdDt theId) {
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
|
|
Patient patient = new Patient();
|
|
patient.addName().addFamily("Smith");
|
|
|
|
// Set the ID and version
|
|
patient.setId(theId.withVersion("1"));
|
|
|
|
// ...populate the rest...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: history
|
|
|
|
|
|
//START SNIPPET: vread
|
|
@Read(version=true)
|
|
public Patient readOrVread(@IdParam IdDt theId) {
|
|
Patient retVal = new Patient();
|
|
|
|
if (theId.hasVersionIdPart()) {
|
|
// this is a vread
|
|
} else {
|
|
// this is a read
|
|
}
|
|
|
|
// ...populate...
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: vread
|
|
|
|
//START SNIPPET: searchStringParam
|
|
@Search()
|
|
public List<Patient> searchByLastName(@RequiredParam(name=Patient.SP_FAMILY) StringParam theFamily) {
|
|
String valueToMatch = theFamily.getValue();
|
|
|
|
if (theFamily.isExact()) {
|
|
// Do an exact match search
|
|
} else {
|
|
// Do a fuzzy search if possible
|
|
}
|
|
|
|
// ...populate...
|
|
Patient patient = new Patient();
|
|
patient.addIdentifier().setSystem("urn:mrns").setValue("12345").setLabel("MRN 12345");
|
|
patient.addName().addFamily("Smith").addGiven("Tester").addGiven("Q");
|
|
// ...etc...
|
|
|
|
// Every returned resource must have its logical ID set. If the server
|
|
// supports versioning, that should be set too
|
|
String logicalId = "4325";
|
|
String versionId = "2"; // optional
|
|
patient.setId(new IdDt("Patient", logicalId, versionId));
|
|
|
|
/*
|
|
* This is obviously a fairly contrived example since we are always
|
|
* just returning the same hardcoded patient, but in a real scenario
|
|
* you could return as many resources as you wanted, and they
|
|
* should actually match the given search criteria.
|
|
*/
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
retVal.add(patient);
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchStringParam
|
|
|
|
//START SNIPPET: searchNamedQuery
|
|
@Search(queryName="namedQuery1")
|
|
public List<Patient> searchByNamedQuery(@RequiredParam(name="someparam") StringParam theSomeParam) {
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchNamedQuery
|
|
|
|
//START SNIPPET: searchComposite
|
|
@Search()
|
|
public List<Observation> searchByComposite(
|
|
@RequiredParam(name=Observation.SP_NAME_VALUE_DATE, compositeTypes= {TokenParam.class, DateParam.class})
|
|
CompositeParam<TokenParam, DateParam> theParam) {
|
|
// Each of the two values in the composite param are accessible separately.
|
|
// In the case of Observation's name-value-date, the left is a string and
|
|
// the right is a date.
|
|
TokenParam observationName = theParam.getLeftValue();
|
|
DateParam observationValue = theParam.getRightValue();
|
|
|
|
List<Observation> retVal = new ArrayList<Observation>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchComposite
|
|
|
|
|
|
//START SNIPPET: searchIdentifierParam
|
|
@Search()
|
|
public List<Patient> searchByIdentifier(@RequiredParam(name=Patient.SP_IDENTIFIER) TokenParam theId) {
|
|
String identifierSystem = theId.getSystem();
|
|
String identifier = theId.getValue();
|
|
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchIdentifierParam
|
|
|
|
//START SNIPPET: searchOptionalParam
|
|
@Search()
|
|
public List<Patient> searchByNames( @RequiredParam(name=Patient.SP_FAMILY) StringParam theFamilyName,
|
|
@OptionalParam(name=Patient.SP_GIVEN) StringParam theGivenName ) {
|
|
String familyName = theFamilyName.getValue();
|
|
String givenName = theGivenName != null ? theGivenName.getValue() : null;
|
|
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchOptionalParam
|
|
|
|
//START SNIPPET: searchWithDocs
|
|
@Description(shortDefinition="This search finds all patient resources matching a given name combination")
|
|
@Search()
|
|
public List<Patient> searchWithDocs(
|
|
@Description(shortDefinition="This is the patient's last name - Supports partial matches")
|
|
@RequiredParam(name=Patient.SP_FAMILY) StringParam theFamilyName,
|
|
|
|
@Description(shortDefinition="This is the patient's given names")
|
|
@OptionalParam(name=Patient.SP_GIVEN) StringParam theGivenName ) {
|
|
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchWithDocs
|
|
|
|
|
|
//START SNIPPET: searchMultiple
|
|
@Search()
|
|
public List<Observation> searchByObservationNames(
|
|
@RequiredParam(name=Observation.SP_NAME) TokenOrListParam theCodings ) {
|
|
|
|
// The list here will contain 0..* codings, and any observations which match any of the
|
|
// given codings should be returned
|
|
List<BaseCodingDt> wantedCodings = theCodings.getListAsCodings();
|
|
|
|
List<Observation> retVal = new ArrayList<Observation>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchMultiple
|
|
|
|
|
|
//START SNIPPET: searchMultipleAnd
|
|
@Search()
|
|
public List<Patient> searchByPatientAddress(
|
|
@RequiredParam(name=Patient.SP_ADDRESS) StringAndListParam theAddressParts ) {
|
|
|
|
// StringAndListParam is a container for 0..* StringOrListParam, which is in turn a
|
|
// container for 0..* strings. It is a little bit weird to understand at first, but think of the
|
|
// StringAndListParam to be an AND list with multiple OR lists inside it. So you will need
|
|
// to return results which match at least one string within every OR list.
|
|
List<StringOrListParam> wantedCodings = theAddressParts.getValuesAsQueryTokens();
|
|
for (StringOrListParam nextOrList : wantedCodings) {
|
|
List<StringParam> queryTokens = nextOrList.getValuesAsQueryTokens();
|
|
// Only return results that match at least one of the tokens in the list below
|
|
for (StringParam nextString : queryTokens) {
|
|
// ....check for match...
|
|
}
|
|
}
|
|
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: searchMultipleAnd
|
|
|
|
|
|
//START SNIPPET: dates
|
|
@Search()
|
|
public List<Patient> searchByObservationNames( @RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theDate ) {
|
|
QuantityCompararatorEnum comparator = theDate.getComparator(); // e.g. <=
|
|
Date date = theDate.getValue(); // e.g. 2011-01-02
|
|
TemporalPrecisionEnum precision = theDate.getPrecision(); // e.g. DAY
|
|
|
|
List<Patient> retVal = new ArrayList<Patient>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: dates
|
|
|
|
public void dateClientExample() {
|
|
ITestClient client = provideTc();
|
|
//START SNIPPET: dateClient
|
|
DateParam param = new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02");
|
|
List<Patient> response = client.getPatientByDob(param);
|
|
//END SNIPPET: dateClient
|
|
}
|
|
|
|
//START SNIPPET: dateRange
|
|
@Search()
|
|
public List<Observation> searchByDateRange(
|
|
@RequiredParam(name=Observation.SP_DATE) DateRangeParam theRange ) {
|
|
|
|
Date from = theRange.getLowerBoundAsInstant();
|
|
Date to = theRange.getUpperBoundAsInstant();
|
|
|
|
List<Observation> retVal = new ArrayList<Observation>();
|
|
// ...populate...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: dateRange
|
|
|
|
|
|
private ITestClient provideTc() {
|
|
return null;
|
|
}
|
|
@Override
|
|
public Class<? extends IResource> getResourceType() {
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
//START SNIPPET: pathSpec
|
|
@Search()
|
|
public List<DiagnosticReport> getDiagnosticReport(
|
|
@RequiredParam(name=DiagnosticReport.SP_IDENTIFIER)
|
|
TokenParam theIdentifier,
|
|
|
|
@IncludeParam(allow= {"DiagnosticReport.subject"})
|
|
Set<Include> theIncludes ) {
|
|
|
|
List<DiagnosticReport> retVal = new ArrayList<DiagnosticReport>();
|
|
|
|
// Assume this method exists and loads the report from the DB
|
|
DiagnosticReport report = loadSomeDiagnosticReportFromDatabase(theIdentifier);
|
|
|
|
// If the client has asked for the subject to be included:
|
|
if (theIncludes.contains(new Include("DiagnosticReport.subject"))) {
|
|
|
|
// The resource reference should contain the ID of the patient
|
|
IdDt subjectId = report.getSubject().getReference();
|
|
|
|
// So load the patient ID and return it
|
|
Patient subject = loadSomePatientFromDatabase(subjectId);
|
|
report.getSubject().setResource(subject);
|
|
|
|
}
|
|
|
|
retVal.add(report);
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: pathSpec
|
|
|
|
|
|
//START SNIPPET: pathSpecSimple
|
|
@Search()
|
|
public List<DiagnosticReport> getDiagnosticReport(
|
|
@RequiredParam(name=DiagnosticReport.SP_IDENTIFIER)
|
|
TokenParam theIdentifier,
|
|
|
|
@IncludeParam(allow= {"DiagnosticReport.subject"})
|
|
String theInclude ) {
|
|
|
|
List<DiagnosticReport> retVal = new ArrayList<DiagnosticReport>();
|
|
|
|
// Assume this method exists and loads the report from the DB
|
|
DiagnosticReport report = loadSomeDiagnosticReportFromDatabase(theIdentifier);
|
|
|
|
// If the client has asked for the subject to be included:
|
|
if ("DiagnosticReport.subject".equals(theInclude)) {
|
|
|
|
// The resource reference should contain the ID of the patient
|
|
IdDt subjectId = report.getSubject().getReference();
|
|
|
|
// So load the patient ID and return it
|
|
Patient subject = loadSomePatientFromDatabase(subjectId);
|
|
report.getSubject().setResource(subject);
|
|
|
|
}
|
|
|
|
retVal.add(report);
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: pathSpecSimple
|
|
|
|
//START SNIPPET: quantity
|
|
@Search()
|
|
public List<Observation> getObservationsByQuantity(
|
|
@RequiredParam(name=Observation.SP_VALUE_QUANTITY) QuantityParam theQuantity) {
|
|
|
|
List<Observation> retVal = new ArrayList<Observation>();
|
|
|
|
QuantityCompararatorEnum comparator = theQuantity.getComparator();
|
|
DecimalDt value = theQuantity.getValue();
|
|
String units = theQuantity.getUnits();
|
|
// .. Apply these parameters ..
|
|
|
|
// ... populate ...
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: quantity
|
|
|
|
private DiagnosticReport loadSomeDiagnosticReportFromDatabase(TokenParam theIdentifier) {
|
|
return null;
|
|
}
|
|
|
|
private Patient loadSomePatientFromDatabase(IdDt theId) {
|
|
return null;
|
|
}
|
|
|
|
|
|
//START SNIPPET: create
|
|
@Create
|
|
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
|
|
|
/*
|
|
* First we might want to do business validation. The UnprocessableEntityException
|
|
* results in an HTTP 422, which is appropriate for business rule failure
|
|
*/
|
|
if (thePatient.getIdentifierFirstRep().isEmpty()) {
|
|
/* It is also possible to pass an OperationOutcome resource
|
|
* to the UnprocessableEntityException if you want to return
|
|
* a custom populated OperationOutcome. Otherwise, a simple one
|
|
* is created using the string supplied below.
|
|
*/
|
|
throw new UnprocessableEntityException("No identifier supplied");
|
|
}
|
|
|
|
// Save this patient to the database...
|
|
savePatientToDatabase(thePatient);
|
|
|
|
// This method returns a MethodOutcome object which contains
|
|
// the ID (composed of the type Patient, the logical ID 3746, and the
|
|
// version ID 1)
|
|
MethodOutcome retVal = new MethodOutcome();
|
|
retVal.setId(new IdDt("Patient", "3746", "1"));
|
|
|
|
// You can also add an OperationOutcome resource to return
|
|
// This part is optional though:
|
|
OperationOutcome outcome = new OperationOutcome();
|
|
outcome.addIssue().setDetails("One minor issue detected");
|
|
retVal.setOperationOutcome(outcome);
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: create
|
|
|
|
|
|
//START SNIPPET: createClient
|
|
@Create
|
|
public abstract MethodOutcome createNewPatient(@ResourceParam Patient thePatient);
|
|
//END SNIPPET: createClient
|
|
|
|
//START SNIPPET: update
|
|
@Update
|
|
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {
|
|
|
|
/*
|
|
* First we might want to do business validation. The UnprocessableEntityException
|
|
* results in an HTTP 422, which is appropriate for business rule failure
|
|
*/
|
|
if (thePatient.getIdentifierFirstRep().isEmpty()) {
|
|
/* It is also possible to pass an OperationOutcome resource
|
|
* to the UnprocessableEntityException if you want to return
|
|
* a custom populated OperationOutcome. Otherwise, a simple one
|
|
* is created using the string supplied below.
|
|
*/
|
|
throw new UnprocessableEntityException("No identifier supplied");
|
|
}
|
|
|
|
String versionId = theId.getVersionIdPart();
|
|
if (versionId != null) {
|
|
// If the client passed in a version number in an If-Match header, they are
|
|
// doing a version-aware update. You may wish to throw an exception if the supplied
|
|
// version is not the latest version. Note that as of DSTU2 the FHIR specification uses
|
|
// ETags and If-Match to handle version aware updates, so PreconditionFailedException (HTTP 412)
|
|
// is used instead of ResourceVersionConflictException (HTTP 409)
|
|
if (detectedVersionConflict) {
|
|
throw new PreconditionFailedException("Unexpected version");
|
|
}
|
|
}
|
|
|
|
// Save this patient to the database...
|
|
savePatientToDatabase(theId, thePatient);
|
|
|
|
// This method returns a MethodOutcome object which contains
|
|
// the ID and Version ID for the newly saved resource
|
|
MethodOutcome retVal = new MethodOutcome();
|
|
String newVersion = "2"; // may be null if the server is not version aware
|
|
retVal.setId(theId.withVersion(newVersion));
|
|
|
|
// You can also add an OperationOutcome resource to return
|
|
// This part is optional though:
|
|
OperationOutcome outcome = new OperationOutcome();
|
|
outcome.addIssue().setDetails("One minor issue detected");
|
|
retVal.setOperationOutcome(outcome);
|
|
|
|
// If your server supports creating resources during an update if they don't already exist
|
|
// (this is not mandatory and may not be desirable anyhow) you can flag in the response
|
|
// that this was a creation as follows:
|
|
// retVal.setCreated(true);
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: update
|
|
|
|
//START SNIPPET: updateClient
|
|
@Update
|
|
public abstract MethodOutcome updateSomePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient);
|
|
//END SNIPPET: updateClient
|
|
|
|
//START SNIPPET: validate
|
|
@Validate
|
|
public MethodOutcome validatePatient(@ResourceParam Patient thePatient) {
|
|
|
|
// Actually do our validation: The UnprocessableEntityException
|
|
// results in an HTTP 422, which is appropriate for business rule failure
|
|
if (thePatient.getIdentifierFirstRep().isEmpty()) {
|
|
/* It is also possible to pass an OperationOutcome resource
|
|
* to the UnprocessableEntityException if you want to return
|
|
* a custom populated OperationOutcome. Otherwise, a simple one
|
|
* is created using the string supplied below.
|
|
*/
|
|
throw new UnprocessableEntityException("No identifier supplied");
|
|
}
|
|
|
|
// This method returns a MethodOutcome object
|
|
MethodOutcome retVal = new MethodOutcome();
|
|
|
|
// You may also add an OperationOutcome resource to return
|
|
// This part is optional though:
|
|
OperationOutcome outcome = new OperationOutcome();
|
|
outcome.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDetails("One minor issue detected");
|
|
retVal.setOperationOutcome(outcome);
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: validate
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) throws DataFormatException, IOException {
|
|
//nothing
|
|
}
|
|
|
|
|
|
private void savePatientToDatabase(Patient thePatient) {
|
|
// nothing
|
|
}
|
|
private void savePatientToDatabase(IdDt theId, Patient thePatient) {
|
|
// nothing
|
|
}
|
|
|
|
//START SNIPPET: metadataProvider
|
|
public class ConformanceProvider {
|
|
|
|
@Metadata
|
|
public Conformance getServerMetadata() {
|
|
Conformance retVal = new Conformance();
|
|
// ..populate..
|
|
return retVal;
|
|
}
|
|
|
|
}
|
|
//END SNIPPET: metadataProvider
|
|
|
|
|
|
|
|
//START SNIPPET: metadataClient
|
|
public interface MetadataClient extends IRestfulClient {
|
|
|
|
@Metadata
|
|
Conformance getServerMetadata();
|
|
|
|
// ....Other methods can also be added as usual....
|
|
|
|
}
|
|
//END SNIPPET: metadataClient
|
|
|
|
//START SNIPPET: historyClient
|
|
public interface HistoryClient extends IBasicClient {
|
|
/** Server level (history of ALL resources) */
|
|
@History
|
|
Bundle getHistoryServer();
|
|
|
|
/** Type level (history of all resources of a given type) */
|
|
@History(type=Patient.class)
|
|
Bundle getHistoryPatientType();
|
|
|
|
/** Instance level (history of a specific resource instance by type and ID) */
|
|
@History(type=Patient.class)
|
|
Bundle getHistoryPatientInstance(@IdParam IdDt theId);
|
|
|
|
/**
|
|
* Either (or both) of the "since" and "count" paramaters can
|
|
* also be included in any of the methods above.
|
|
*/
|
|
@History
|
|
Bundle getHistoryServerWithCriteria(@Since Date theDate, @Count Integer theCount);
|
|
|
|
}
|
|
//END SNIPPET: historyClient
|
|
|
|
|
|
public void bbbbb() throws DataFormatException, IOException {
|
|
//START SNIPPET: metadataClientUsage
|
|
FhirContext ctx = new FhirContext();
|
|
MetadataClient client = ctx.newRestfulClient(MetadataClient.class, "http://spark.furore.com/fhir");
|
|
Conformance metadata = client.getServerMetadata();
|
|
System.out.println(ctx.newXmlParser().encodeResourceToString(metadata));
|
|
//END SNIPPET: metadataClientUsage
|
|
}
|
|
|
|
//START SNIPPET: readTags
|
|
@Read()
|
|
public Patient readPatient(@IdParam IdDt theId) {
|
|
Patient retVal = new Patient();
|
|
|
|
// ..populate demographics, contact, or anything else you usually would..
|
|
|
|
// Create a TagList and place a complete list of the patient's tags inside
|
|
TagList tags = new TagList();
|
|
tags.addTag("http://animals", "Dog", "Canine Patient"); // TODO: more realistic example
|
|
tags.addTag("http://personality", "Friendly", "Friendly"); // TODO: more realistic example
|
|
|
|
// The tags are then stored in the Patient resource instance
|
|
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tags);
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: readTags
|
|
|
|
//START SNIPPET: clientReadInterface
|
|
private interface IPatientClient extends IBasicClient
|
|
{
|
|
/** Read a patient from a server by ID */
|
|
@Read
|
|
Patient readPatient(@IdParam IdDt theId);
|
|
|
|
// Only one method is shown here, but many methods may be
|
|
// added to the same client interface!
|
|
}
|
|
//END SNIPPET: clientReadInterface
|
|
|
|
public void clientRead() {
|
|
//START SNIPPET: clientReadTags
|
|
IPatientClient client = new FhirContext().newRestfulClient(IPatientClient.class, "http://foo/fhir");
|
|
Patient patient = client.readPatient(new IdDt("1234"));
|
|
|
|
// Access the tag list
|
|
TagList tagList = (TagList) patient.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
|
|
for (Tag next : tagList) {
|
|
// ..process the tags somehow..
|
|
}
|
|
//END SNIPPET: clientReadTags
|
|
|
|
//START SNIPPET: clientCreateTags
|
|
Patient newPatient = new Patient();
|
|
|
|
// Populate the resource object
|
|
newPatient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setValue("123");
|
|
newPatient.addName().addFamily("Jones").addGiven("Frank");
|
|
|
|
// Populate tags
|
|
TagList tags = new TagList();
|
|
tags.addTag("http://animals", "Dog", "Canine Patient"); // TODO: more realistic example
|
|
tags.addTag("http://personality", "Friendly", "Friendly"); // TODO: more realistic example
|
|
newPatient.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tags);
|
|
|
|
// ...invoke the create method on the client...
|
|
//END SNIPPET: clientCreateTags
|
|
}
|
|
|
|
//START SNIPPET: createTags
|
|
@Create
|
|
public MethodOutcome createPatientResource(@ResourceParam Patient thePatient) {
|
|
|
|
// ..save the resouce..
|
|
IdDt id = new IdDt("123"); // the new databse primary key for this resource
|
|
|
|
// Get the tag list
|
|
TagList tags = (TagList) thePatient.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
|
|
for (Tag tag : tags) {
|
|
// process/save each tag somehow
|
|
}
|
|
|
|
return new MethodOutcome(id);
|
|
}
|
|
//END SNIPPET: createTags
|
|
|
|
//START SNIPPET: tagMethodProvider
|
|
public class TagMethodProvider
|
|
{
|
|
/** Return a list of all tags that exist on the server */
|
|
@GetTags
|
|
public TagList getAllTagsOnServer() {
|
|
return new TagList(); // populate this
|
|
}
|
|
|
|
/** Return a list of all tags that exist on at least one instance
|
|
* of the given resource type */
|
|
@GetTags(type=Patient.class)
|
|
public TagList getTagsForAllResourcesOfResourceType() {
|
|
return new TagList(); // populate this
|
|
}
|
|
|
|
/** Return a list of all tags that exist on a specific instance
|
|
* of the given resource type */
|
|
@GetTags(type=Patient.class)
|
|
public TagList getTagsForResources(@IdParam IdDt theId) {
|
|
return new TagList(); // populate this
|
|
}
|
|
|
|
/** Return a list of all tags that exist on a specific version
|
|
* of the given resource type */
|
|
@GetTags(type=Patient.class)
|
|
public TagList getTagsForResourceVersion(@IdParam IdDt theId) {
|
|
return new TagList(); // populate this
|
|
}
|
|
|
|
/** Add tags to a resource */
|
|
@AddTags(type=Patient.class)
|
|
public void getTagsForResourceVersion(@IdParam IdDt theId,
|
|
@TagListParam TagList theTagList) {
|
|
// add tags
|
|
}
|
|
|
|
/** Add tags to a resource version */
|
|
@AddTags(type=Patient.class)
|
|
public void addTagsToResourceVersion(@IdParam IdDt theId,
|
|
@TagListParam TagList theTagList) {
|
|
// add tags
|
|
}
|
|
|
|
/** Remove tags from a resource */
|
|
@DeleteTags(type=Patient.class)
|
|
public void deleteTagsFromResourceVersion(@IdParam IdDt theId,
|
|
@TagListParam TagList theTagList) {
|
|
// add tags
|
|
}
|
|
|
|
}
|
|
//END SNIPPET: tagMethodProvider
|
|
|
|
//START SNIPPET: transaction
|
|
@Transaction
|
|
public List<IResource> transaction(@TransactionParam List<IResource> theResources) {
|
|
// theResources will contain a complete bundle of all resources to persist
|
|
// in a single transaction
|
|
for (IResource next : theResources) {
|
|
InstantDt deleted = (InstantDt) next.getResourceMetadata().get(ResourceMetadataKeyEnum.DELETED_AT);
|
|
if (deleted != null && deleted.isEmpty() == false) {
|
|
// delete this resource
|
|
} else {
|
|
// create or update this resource
|
|
}
|
|
}
|
|
|
|
// According to the specification, a bundle must be returned. This bundle will contain
|
|
// all of the created/updated/deleted resources, including their new/updated identities.
|
|
//
|
|
// The returned list must be the exact same size as the list of resources
|
|
// passed in, and it is acceptable to return the same list instance that was
|
|
// passed in.
|
|
List<IResource> retVal = new ArrayList<IResource>(theResources);
|
|
for (IResource next : theResources) {
|
|
/*
|
|
* Populate each returned resource with the new ID for that resource,
|
|
* including the new version if the server supports versioning.
|
|
*/
|
|
IdDt newId = new IdDt("Patient", "1", "2");
|
|
next.setId(newId);
|
|
}
|
|
|
|
// If wanted, you may optionally also return an OperationOutcome resource
|
|
// If present, the OperationOutcome must come first in the returned list.
|
|
OperationOutcome oo = new OperationOutcome();
|
|
oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Completed successfully");
|
|
retVal.add(0, oo);
|
|
|
|
return retVal;
|
|
}
|
|
//END SNIPPET: transaction
|
|
|
|
|
|
}
|
|
|
|
|