001package org.hl7.fhir.r4.hapi.fluentpath; 002 003import ca.uhn.fhir.fhirpath.IFhirPathEvaluationContext; 004import ca.uhn.fhir.i18n.Msg; 005import ca.uhn.fhir.context.FhirContext; 006import ca.uhn.fhir.context.support.IValidationSupport; 007import ca.uhn.fhir.fhirpath.FhirPathExecutionException; 008import ca.uhn.fhir.fhirpath.IFhirPath; 009import org.hl7.fhir.exceptions.FHIRException; 010import org.hl7.fhir.exceptions.PathEngineException; 011import org.hl7.fhir.instance.model.api.IBase; 012import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext; 013import org.hl7.fhir.r4.model.Base; 014import org.hl7.fhir.r4.model.IdType; 015import org.hl7.fhir.r4.model.TypeDetails; 016import org.hl7.fhir.r4.model.ValueSet; 017import org.hl7.fhir.r4.utils.FHIRPathEngine; 018 019import javax.annotation.Nonnull; 020import java.util.List; 021import java.util.Optional; 022 023public class FhirPathR4 implements IFhirPath { 024 025 private final FHIRPathEngine myEngine; 026 027 public FhirPathR4(FhirContext theCtx) { 028 IValidationSupport validationSupport = theCtx.getValidationSupport(); 029 myEngine = new FHIRPathEngine(new HapiWorkerContext(theCtx, validationSupport)); 030 // These changes are to make the FP evaluation non-strict 031 myEngine.setDoNotEnforceAsCaseSensitive(true); 032 myEngine.setDoNotEnforceAsSingletonRule(true); 033 } 034 035 @SuppressWarnings("unchecked") 036 @Override 037 public <T extends IBase> List<T> evaluate(IBase theInput, String thePath, Class<T> theReturnType) { 038 List<Base> result; 039 try { 040 result = myEngine.evaluate((Base) theInput, thePath); 041 } catch (FHIRException e) { 042 throw new FhirPathExecutionException(Msg.code(255) + e); 043 } 044 045 for (Base next : result) { 046 if (!theReturnType.isAssignableFrom(next.getClass())) { 047 throw new FhirPathExecutionException(Msg.code(256) + "FluentPath expression \"" + thePath + "\" returned unexpected type " + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName()); 048 } 049 } 050 051 return (List<T>) result; 052 } 053 054 @Override 055 public <T extends IBase> Optional<T> evaluateFirst(IBase theInput, String thePath, Class<T> theReturnType) { 056 return evaluate(theInput, thePath, theReturnType).stream().findFirst(); 057 } 058 059 @Override 060 public void parse(String theExpression) { 061 myEngine.parse(theExpression); 062 } 063 064 @Override 065 public void setEvaluationContext(@Nonnull IFhirPathEvaluationContext theEvaluationContext) { 066 myEngine.setHostServices(new FHIRPathEngine.IEvaluationContext(){ 067 068 @Override 069 public List<Base> resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { 070 return null; 071 } 072 073 @Override 074 public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException { 075 return null; 076 } 077 078 @Override 079 public boolean log(String argument, List<Base> focus) { 080 return false; 081 } 082 083 @Override 084 public FunctionDetails resolveFunction(String functionName) { 085 return null; 086 } 087 088 @Override 089 public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException { 090 return null; 091 } 092 093 @Override 094 public List<Base> executeFunction(Object appContext, List<Base> focus, String functionName, List<List<Base>> parameters) { 095 return null; 096 } 097 098 @Override 099 public Base resolveReference(Object appContext, String theUrl, Base theRefContext) throws FHIRException { 100 return (Base)theEvaluationContext.resolveReference(new IdType(theUrl), theRefContext); 101 } 102 103 @Override 104 public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException { 105 return false; 106 } 107 108 @Override 109 public ValueSet resolveValueSet(Object appContext, String url) { 110 return null; 111 } 112 }); 113 } 114 115 116}