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