
001package org.hl7.fhir.r5.hapi.fhirpath; 002 003import ca.uhn.fhir.context.FhirContext; 004import ca.uhn.fhir.context.support.IValidationSupport; 005import ca.uhn.fhir.fhirpath.FhirPathExecutionException; 006import ca.uhn.fhir.fhirpath.IFhirPath; 007import ca.uhn.fhir.fhirpath.IFhirPathEvaluationContext; 008import ca.uhn.fhir.i18n.Msg; 009import org.hl7.fhir.exceptions.FHIRException; 010import org.hl7.fhir.exceptions.PathEngineException; 011import org.hl7.fhir.instance.model.api.IBase; 012import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext; 013import org.hl7.fhir.r5.model.Base; 014import org.hl7.fhir.r5.model.ExpressionNode; 015import org.hl7.fhir.r5.model.IdType; 016import org.hl7.fhir.r5.model.TypeDetails; 017import org.hl7.fhir.r5.model.ValueSet; 018import org.hl7.fhir.r5.utils.FHIRPathEngine; 019import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses; 020 021import java.util.List; 022import java.util.Optional; 023import javax.annotation.Nonnull; 024 025public class FhirPathR5 implements IFhirPath { 026 027 private final FHIRPathEngine myEngine; 028 029 public FhirPathR5(FhirContext theCtx) { 030 IValidationSupport validationSupport = theCtx.getValidationSupport(); 031 myEngine = new FHIRPathEngine(new HapiWorkerContext(theCtx, validationSupport)); 032 myEngine.setDoNotEnforceAsSingletonRule(true); 033 } 034 035 @SuppressWarnings({"unchecked", "unchecked"}) 036 @Override 037 public <T extends IBase> List<T> evaluate(IBase theInput, String thePath, Class<T> theReturnType) { 038 ExpressionNode parsed; 039 try { 040 parsed = myEngine.parse(thePath); 041 } catch (FHIRException e) { 042 throw new FhirPathExecutionException(Msg.code(2411) + e); 043 } 044 return (List<T>) evaluate(theInput, parsed, theReturnType); 045 } 046 047 @SuppressWarnings("unchecked") 048 @Override 049 public <T extends IBase> List<T> evaluate( 050 IBase theInput, IParsedExpression theParsedExpression, Class<T> theReturnType) { 051 ExpressionNode expressionNode = ((ParsedExpression) theParsedExpression).myParsedExpression; 052 return (List<T>) evaluate(theInput, expressionNode, theReturnType); 053 } 054 055 @Nonnull 056 private <T extends IBase> List<Base> evaluate( 057 IBase theInput, ExpressionNode expressionNode, Class<T> theReturnType) { 058 List<Base> result; 059 try { 060 result = myEngine.evaluate((Base) theInput, expressionNode); 061 } catch (FHIRException e) { 062 throw new FhirPathExecutionException(Msg.code(198) + e); 063 } 064 065 for (IBase next : result) { 066 if (!theReturnType.isAssignableFrom(next.getClass())) { 067 throw new FhirPathExecutionException(Msg.code(199) + "FhirPath expression returned unexpected type " 068 + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName()); 069 } 070 } 071 return result; 072 } 073 074 @Override 075 public <T extends IBase> Optional<T> evaluateFirst(IBase theInput, String thePath, Class<T> theReturnType) { 076 return evaluate(theInput, thePath, theReturnType).stream().findFirst(); 077 } 078 079 @Override 080 public <T extends IBase> Optional<T> evaluateFirst( 081 IBase theInput, IParsedExpression theParsedExpression, Class<T> theReturnType) { 082 return evaluate(theInput, theParsedExpression, theReturnType).stream().findFirst(); 083 } 084 085 @Override 086 public IParsedExpression parse(String theExpression) { 087 return new ParsedExpression(myEngine.parse(theExpression)); 088 } 089 090 @Override 091 public void setEvaluationContext(@Nonnull IFhirPathEvaluationContext theEvaluationContext) { 092 myEngine.setHostServices(new FHIRPathEngine.IEvaluationContext() { 093 094 @Override 095 public List<Base> resolveConstant(Object appContext, String name, boolean beforeContext) 096 throws PathEngineException { 097 return null; 098 } 099 100 @Override 101 public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException { 102 return null; 103 } 104 105 @Override 106 public boolean log(String argument, List<Base> focus) { 107 return false; 108 } 109 110 @Override 111 public FHIRPathUtilityClasses.FunctionDetails resolveFunction(String functionName) { 112 return null; 113 } 114 115 @Override 116 public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) 117 throws PathEngineException { 118 return null; 119 } 120 121 @Override 122 public List<Base> executeFunction( 123 Object appContext, List<Base> focus, String functionName, List<List<Base>> parameters) { 124 return null; 125 } 126 127 @Override 128 public Base resolveReference(Object appContext, String theUrl, Base refContext) throws FHIRException { 129 return (Base) theEvaluationContext.resolveReference(new IdType(theUrl), refContext); 130 } 131 132 @Override 133 public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException { 134 return false; 135 } 136 137 @Override 138 public ValueSet resolveValueSet(Object appContext, String url) { 139 return null; 140 } 141 }); 142 } 143 144 private static class ParsedExpression implements IParsedExpression { 145 146 private final ExpressionNode myParsedExpression; 147 148 public ParsedExpression(ExpressionNode theParsedExpression) { 149 myParsedExpression = theParsedExpression; 150 } 151 } 152}