add command line demo app
This commit is contained in:
parent
c5ac82fd09
commit
54dcbe8a9f
|
@ -0,0 +1,335 @@
|
|||
package org.hl7.fhir.r4.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.formats.JsonParser;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement;
|
||||
import org.hl7.fhir.r4.model.CodeType;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.Condition;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.Immunization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Period;
|
||||
import org.hl7.fhir.r4.model.Procedure;
|
||||
import org.hl7.fhir.r4.model.Property;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.Type;
|
||||
import org.hl7.fhir.r4.utils.client.FHIRToolingClient;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
|
||||
public class CmdLineApp {
|
||||
|
||||
private FHIRToolingClient client;
|
||||
private String currentId;
|
||||
private Resource currentResource;
|
||||
private SimpleWorkerContext context;
|
||||
private FHIRPathEngine fpe;
|
||||
|
||||
public static void main(String[] args) throws IOException, Exception {
|
||||
new CmdLineApp().execute();
|
||||
}
|
||||
|
||||
private void execute() throws IOException {
|
||||
System.out.print("Loading...");
|
||||
NpmPackage npm = new FilesystemPackageCacheManager(true).loadPackage("hl7.fhir.r4.core");
|
||||
context = SimpleWorkerContext.fromPackage(npm);
|
||||
fpe = new FHIRPathEngine(context);
|
||||
System.out.println(" Done");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
genMenu();
|
||||
boolean finished = false;
|
||||
do {
|
||||
System.out.print("> ");
|
||||
String cmd = reader.readLine();
|
||||
String[] p = cmd.split("\\s+");
|
||||
try {
|
||||
if (p.length == 1 && p[0].equals("x")) {
|
||||
finished = true;
|
||||
} else if (p.length == 1 && p[0].equals("?")) {
|
||||
genMenu();
|
||||
} else if (p.length >= 1 && p[0].equals("c")) {
|
||||
if (p.length == 1) {
|
||||
connectToServer("http://hapi.fhir.org/baseR4");
|
||||
} else {
|
||||
connectToServer(p[1]);
|
||||
}
|
||||
} else if (p.length >= 1 && p[0].equals("imm")) {
|
||||
if (p.length == 1) {
|
||||
if (currentResource == null || !(currentResource instanceof Patient)) {
|
||||
throw new FHIRException("Current resource must be a patient for this command");
|
||||
}
|
||||
getImmunizations();
|
||||
} else {
|
||||
select("Immunization", p[1]);
|
||||
}
|
||||
} else if (p.length >= 1 && p[0].equals("cnd")) {
|
||||
if (p.length == 1) {
|
||||
if (currentResource == null || !(currentResource instanceof Patient)) {
|
||||
throw new FHIRException("Current resource must be a patient for this command");
|
||||
}
|
||||
getConditions();
|
||||
} else {
|
||||
select("Condition", p[1]);
|
||||
}
|
||||
} else if (p.length >= 1 && p[0].equals("prc")) {
|
||||
if (p.length == 1) {
|
||||
if (currentResource == null || !(currentResource instanceof Patient)) {
|
||||
throw new FHIRException("Current resource must be a patient for this command");
|
||||
}
|
||||
getProcedures();
|
||||
} else {
|
||||
select("Procedure", p[1]);
|
||||
}
|
||||
} else if (p.length >= 1 && p[0].equals("v")) {
|
||||
if (p.length == 1) {
|
||||
viewResource();
|
||||
} else {
|
||||
viewResource(p[1]);
|
||||
}
|
||||
} else if (p.length >= 2 && p[0].equals("s")) {
|
||||
search(p);
|
||||
} else if (p.length >= 2 && p[0].equals("p")) {
|
||||
select("Patient", p[1]);
|
||||
} else if (p.length == 3 && p[0].equals("e")) {
|
||||
edit(p[1], p[2]);
|
||||
} else {
|
||||
System.out.println("Command unknown or not understood: "+cmd);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error executing command "+p[0]+": "+e.getMessage());
|
||||
}
|
||||
} while (!finished);
|
||||
|
||||
System.out.println("Finished!");
|
||||
}
|
||||
|
||||
private void getImmunizations() {
|
||||
|
||||
Bundle bnd = client.search("Immunization", "?patient="+currentId);
|
||||
System.out.println(""+bnd.getTotal()+" Immunizations found. Printing "+bnd.getEntry().size());
|
||||
|
||||
for (BundleEntryComponent be : bnd.getEntry()) {
|
||||
Resource imm = be.getResource();
|
||||
System.out.println(summary(imm));
|
||||
}
|
||||
}
|
||||
|
||||
private void getProcedures() {
|
||||
|
||||
Bundle bnd = client.search("Procedure", "?patient="+currentId);
|
||||
System.out.println(""+bnd.getTotal()+" Procedures found. Printing "+bnd.getEntry().size());
|
||||
|
||||
for (BundleEntryComponent be : bnd.getEntry()) {
|
||||
Resource imm = be.getResource();
|
||||
System.out.println(summary(imm));
|
||||
}
|
||||
}
|
||||
|
||||
private void getConditions() {
|
||||
|
||||
Bundle bnd = client.search("Condition", "?patient="+currentId);
|
||||
System.out.println(""+bnd.getTotal()+" Conditions found. Printing "+bnd.getEntry().size());
|
||||
|
||||
for (BundleEntryComponent be : bnd.getEntry()) {
|
||||
Resource imm = be.getResource();
|
||||
System.out.println(summary(imm));
|
||||
}
|
||||
}
|
||||
|
||||
private void edit(String path, String value) {
|
||||
if (path.contains(".")) {
|
||||
List<Base> list = fpe.evaluate(currentResource, fpe.parse(path.substring(0, path.lastIndexOf("."))));
|
||||
if (list.size() == 1) {
|
||||
path = path.substring(path.lastIndexOf(".")+1);
|
||||
Property p = list.get(0).getNamedProperty(path);
|
||||
Base b = makeValue(p, value);
|
||||
list.get(0).setProperty(path, b);
|
||||
} else {
|
||||
throw new FHIRException("Unable to set value at "+path+": "+list.size()+" matches");
|
||||
}
|
||||
} else {
|
||||
Property p = currentResource.getNamedProperty(path);
|
||||
Base b = makeValue(p, value);
|
||||
currentResource.setProperty(path, b);
|
||||
}
|
||||
currentResource = client.update(currentResource);
|
||||
}
|
||||
|
||||
private Base makeValue(Property p, String value) {
|
||||
switch (p.getTypeCode()) {
|
||||
case "boolean" : return new BooleanType(value);
|
||||
case "code" : return new CodeType(value);
|
||||
case "string" : return new StringType(value);
|
||||
}
|
||||
throw new FHIRException("Unhandled type "+p.getTypeCode());
|
||||
}
|
||||
|
||||
private void viewResource(String path) {
|
||||
System.out.println("Current Resource, query = "+path);
|
||||
List<Base> list = fpe.evaluate(currentResource, fpe.parse(path));
|
||||
for (Base b : list) {
|
||||
System.out.println(b.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void viewResource() throws IOException {
|
||||
System.out.println("Current Resource:");
|
||||
System.out.println(new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(currentResource));
|
||||
}
|
||||
|
||||
private void select(String type, String id) {
|
||||
if (type.equals("Patient")) {
|
||||
currentResource = client.fetchResource(Patient.class, id);
|
||||
} else if (type.equals("Immunization")) {
|
||||
currentResource = client.fetchResource(Immunization.class, id);
|
||||
} else if (type.equals("Condition")) {
|
||||
currentResource = client.fetchResource(Condition.class, id);
|
||||
} else if (type.equals("Procedure")) {
|
||||
currentResource = client.fetchResource(Procedure.class, id);
|
||||
} else {
|
||||
throw new FHIRException("Unhandled type "+type);
|
||||
}
|
||||
currentId = type+"/"+id;
|
||||
System.out.println("Resource = "+currentId+" "+summary(currentResource));
|
||||
}
|
||||
|
||||
private String summary(Resource r) {
|
||||
if (r instanceof Patient) {
|
||||
Patient pat = (Patient) r;
|
||||
return pat.getIdBase()+" "+pat.getGender()+" "+pat.getBirthDateElement().asStringValue()+" "+name(pat);
|
||||
}
|
||||
if (r instanceof Immunization) {
|
||||
Immunization imm = (Immunization) r;
|
||||
return imm.getIdBase()+" "+imm.getOccurrenceDateTimeType().asStringValue()+" "+code(imm.getVaccineCode())+" "+imm.getLotNumber()+" ("+imm.getStatus()+")";
|
||||
}
|
||||
if (r instanceof Condition) {
|
||||
Condition cnd = (Condition) r;
|
||||
return cnd.getIdBase()+" "+code(cnd.getClinicalStatus())+" "+code(cnd.getVerificationStatus())+" "+code(cnd.getCode())+" "+cnd.getRecordedDateElement().asStringValue();
|
||||
}
|
||||
if (r instanceof Procedure) {
|
||||
Procedure prc = (Procedure) r;
|
||||
return prc.getIdBase()+" "+prc.getStatusElement().asStringValue()+" "+code(prc.getCode())+" "+code(prc.getCode())+" "+dt(prc.getPerformed());
|
||||
}
|
||||
return "??";
|
||||
}
|
||||
|
||||
private String dt(Type type) {
|
||||
if (type == null) {
|
||||
return "";
|
||||
}
|
||||
if (type.isPrimitive()) {
|
||||
return type.primitiveValue();
|
||||
}
|
||||
if (type instanceof Period) {
|
||||
Period pd = (Period) type;
|
||||
return pd.getStartElement().asStringValue()+" -> "+pd.getEndElement().asStringValue();
|
||||
}
|
||||
return "??";
|
||||
}
|
||||
|
||||
private String code(CodeableConcept cc) {
|
||||
for (Coding c : cc.getCoding()) {
|
||||
if (c.hasSystem()) {
|
||||
String d = c.hasDisplay() ? " ("+c.getDisplay()+")" : "";
|
||||
if (c.hasCode()) {
|
||||
switch (c.getSystem()) {
|
||||
case "http://hl7.org/fhir/sid/cvx": return "CVX "+c.getCode()+d;
|
||||
case "http://snomed.info/sct": return "SCT "+c.getCode()+d;
|
||||
default:
|
||||
if (Utilities.startsWithInList(c.getSystem(), "http://terminology.hl7.org")) {
|
||||
return c.getCode();
|
||||
} else {
|
||||
throw new FHIRException("Unknown system "+c.getSystem());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Coding c : cc.getCoding()) {
|
||||
if (c.hasCode()) {
|
||||
return c.getCode();
|
||||
}
|
||||
}
|
||||
if (cc.hasText()) {
|
||||
return cc.getText();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private void search(String[] p) {
|
||||
if (client == null) {
|
||||
throw new FHIRException("Not connected to to a server");
|
||||
}
|
||||
String search = "?name="+p[1];
|
||||
if (p.length > 2) {
|
||||
search = search +"&gender="+p[2];
|
||||
if (p.length > 3) {
|
||||
search = search +"&dob="+p[3];
|
||||
}
|
||||
}
|
||||
Bundle bnd = client.search("Patient", search);
|
||||
System.out.println(""+bnd.getTotal()+" Patients found. Printing "+bnd.getEntry().size());
|
||||
|
||||
for (BundleEntryComponent be : bnd.getEntry()) {
|
||||
Patient pat = (Patient) be.getResource();
|
||||
System.out.println(summary(pat));
|
||||
}
|
||||
}
|
||||
|
||||
private String name(Patient pat) {
|
||||
if (pat.getName().size() > 0) {
|
||||
return name(pat.getName().get(0));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String name(HumanName n) {
|
||||
if (n.hasText()) {
|
||||
return n.getText();
|
||||
}
|
||||
if (n.hasFamily()) {
|
||||
if (n.hasGiven()) {
|
||||
return n.getGiven().get(0)+" "+n.getFamily().toUpperCase();
|
||||
} else {
|
||||
return n.getFamily().toUpperCase();
|
||||
}
|
||||
}
|
||||
return "??";
|
||||
}
|
||||
|
||||
private void connectToServer(String url) throws URISyntaxException {
|
||||
client = new FHIRToolingClient(url, "FHIR-Command-Line-App");
|
||||
CapabilityStatement cs = client.getCapabilitiesStatementQuick();
|
||||
System.out.println("Connected to "+url+": "+cs.getSoftware().getName()+".");
|
||||
}
|
||||
|
||||
private void genMenu() {
|
||||
System.out.println("Simple Client. Commands you can run:");
|
||||
System.out.println(" c {url} - connect to a server");
|
||||
System.out.println(" s {name} [{gender}] {{dob]} - find a patient record");
|
||||
System.out.println(" p {id} - choose a patient record");
|
||||
System.out.println(" v [{field}] - see a set of field(s) in the current resource, or the whole resource");
|
||||
System.out.println(" e {field} {value} - edit a field in the current resource");
|
||||
System.out.println(" imm [{id}] - get a list of the patient's immunizations, or use the resource for the id (then use e to edit it)");
|
||||
System.out.println(" cnd [{id}] - get a list of the patient's conditions, or use the resource for the id (then use e to edit it)");
|
||||
System.out.println(" prc [{id}] - get a list of the patient's procedures, or use the resource for the id (then use e to edit it)");
|
||||
System.out.println(" ? - print this again");
|
||||
System.out.println(" x - exit");
|
||||
}
|
||||
}
|
|
@ -595,4 +595,23 @@ public class FHIRToolingClient {
|
|||
public void setLanguage(String lang) {
|
||||
this.acceptLang = lang;
|
||||
}
|
||||
|
||||
public Bundle search(String type, String criteria) {
|
||||
return fetchFeed(Utilities.pathURL(base, type+criteria));
|
||||
}
|
||||
|
||||
public <T extends Resource> T fetchResource(Class<T> resourceClass, String id) {
|
||||
org.hl7.fhir.r4.utils.client.network.ResourceRequest<Resource> result = null;
|
||||
try {
|
||||
result = client.issueGetResourceRequest(resourceAddress.resolveGetResource(resourceClass, id),
|
||||
getPreferredResourceFormat(), generateHeaders(), resourceClass.getName()+"/"+id, TIMEOUT_NORMAL);
|
||||
} catch (IOException e) {
|
||||
throw new FHIRException(e);
|
||||
}
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
throw new EFhirClientException("Server returned error code " + result.getHttpStatus(),
|
||||
(OperationOutcome) result.getPayload());
|
||||
}
|
||||
return (T) result.getPayload();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,10 @@ public class ResourceAddress {
|
|||
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) + "/" + opName);
|
||||
}
|
||||
|
||||
public <T extends Resource> URI resolveGetResource(Class<T> resourceClass, String id) {
|
||||
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) + "/" + id);
|
||||
}
|
||||
|
||||
public <T extends Resource> URI resolveOperationUri(Class<T> resourceClass, String opName,
|
||||
Map<String, String> parameters) {
|
||||
return appendHttpParameters(baseServiceUri.resolve(nameForClassWithSlash(resourceClass) + "$" + opName),
|
||||
|
|
Loading…
Reference in New Issue