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}