diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 3a0da77e7..ae6783860 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -1,6 +1,7 @@ package org.hl7.fhir.r5.utils; import java.math.BigDecimal; +import java.rmi.server.LoaderHandler; import java.util.ArrayList; import java.util.Base64; import java.util.Date; @@ -53,6 +54,7 @@ import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException; import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationOptions; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; @@ -159,31 +161,35 @@ public class FHIRPathEngine { @Override public void setIdBase(String value) { } + public Base[] getProperty(int hash, String name, boolean checkValid) throws FHIRException { - if (name.equals("name")) + if (name.equals("name")) { return new Base[]{new StringType(getName())}; - else if (name.equals("namespace")) + } else if (name.equals("namespace")) { return new Base[]{new StringType(getNamespace())}; - else + } else { return super.getProperty(hash, name, checkValid); + } } private String getNamespace() { - if ((instance instanceof Resource)) + if ((instance instanceof Resource)) { return "FHIR"; - else if (!(instance instanceof Element) || ((Element)instance).isDisallowExtensions()) + } else if (!(instance instanceof Element) || ((Element)instance).isDisallowExtensions()) { return "System"; - else + } else { return "FHIR"; + } } private String getName() { - if ((instance instanceof Resource)) + if ((instance instanceof Resource)) { return instance.fhirType(); - else if (!(instance instanceof Element) || ((Element)instance).isDisallowExtensions()) + } else if (!(instance instanceof Element) || ((Element)instance).isDisallowExtensions()) { return Utilities.capitalize(instance.fhirType()); - else + } else { return instance.fhirType(); + } } } @@ -195,6 +201,7 @@ public class FHIRPathEngine { private boolean legacyMode; // some R2 and R3 constraints assume that != is valid for emptty sets, so when running for R2/R3, this is set ot true private ValidationOptions terminologyServiceOptions = new ValidationOptions(); private ProfileUtilities profileUtilities; + private String location; // for error messages // if the fhir path expressions are allowed to use constants beyond those defined in the specification // the application can implement them by providing a constant resolver @@ -294,9 +301,10 @@ public class FHIRPathEngine { this.worker = worker; profileUtilities = new ProfileUtilities(worker, null, null); for (StructureDefinition sd : worker.getStructures()) { - if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && sd.getKind() != StructureDefinitionKind.LOGICAL) + if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && sd.getKind() != StructureDefinitionKind.LOGICAL) { allTypes.put(sd.getName(), sd); - if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { + } + if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { primitiveTypes.add(sd.getName()); } } @@ -316,6 +324,15 @@ public class FHIRPathEngine { this.hostServices = constantResolver; } + public String getLocation() { + return location; + } + + + public void setLocation(String location) { + this.location = location; + } + /** * Given an item, return all the children that conform to the pattern described in name @@ -330,13 +347,16 @@ public class FHIRPathEngine { * @param name * @param result * @throws FHIRException - */ + */ protected void getChildrenByName(Base item, String name, List result) throws FHIRException { - Base[] list = item.listChildrenByName(name, false); - if (list != null) - for (Base v : list) - if (v != null) - result.add(v); + Base[] list = item.listChildrenByName(name, false); + if (list != null) { + for (Base v : list) { + if (v != null) { + result.add(v); + } + } + } } @@ -365,11 +385,13 @@ public class FHIRPathEngine { public ExpressionNode parse(String path, String name) throws FHIRLexerException { FHIRLexer lexer = new FHIRLexer(path, name); - if (lexer.done()) + if (lexer.done()) { throw lexer.error("Path cannot be empty"); + } ExpressionNode result = parseExpression(lexer, true); - if (!lexer.done()) + if (!lexer.done()) { throw lexer.error("Premature ExpressionNode termination at unexpected token \""+lexer.getCurrent()+"\""); + } result.check(); return result; } @@ -400,8 +422,9 @@ public class FHIRPathEngine { */ public ExpressionNodeWithOffset parsePartial(String path, int i) throws FHIRLexerException { FHIRLexer lexer = new FHIRLexer(path, i); - if (lexer.done()) + if (lexer.done()) { throw lexer.error("Path cannot be empty"); + } ExpressionNode result = parseExpression(lexer, true); result.check(); return new ExpressionNodeWithOffset(lexer.getCurrentStart(), result); @@ -434,37 +457,48 @@ public class FHIRPathEngine { */ public TypeDetails check(Object appContext, String resourceType, String context, ExpressionNode expr) throws FHIRLexerException, PathEngineException, DefinitionException { // if context is a path that refers to a type, do that conversion now - TypeDetails types; - if (context == null) { - types = null; // this is a special case; the first path reference will have to resolve to something in the context - } else if (!context.contains(".")) { - StructureDefinition sd = worker.fetchTypeDefinition(context); - types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()); - } else { - String ctxt = context.substring(0, context.indexOf('.')); + TypeDetails types; + if (context == null) { + types = null; // this is a special case; the first path reference will have to resolve to something in the context + } else if (!context.contains(".")) { + StructureDefinition sd = worker.fetchTypeDefinition(context); + types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()); + } else { + String ctxt = context.substring(0, context.indexOf('.')); if (Utilities.isAbsoluteUrl(resourceType)) { ctxt = resourceType.substring(0, resourceType.lastIndexOf("/")+1)+ctxt; } - StructureDefinition sd = worker.fetchResource(StructureDefinition.class, ctxt); - if (sd == null) - throw new PathEngineException("Unknown context "+context); - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); - if (ed == null) - throw new PathEngineException("Unknown context element "+context); - if (ed.fixedType != null) - types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); - else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) - types = new TypeDetails(CollectionStatus.SINGLETON, ctxt+"#"+context); - else { - types = new TypeDetails(CollectionStatus.SINGLETON); - for (TypeRefComponent t : ed.getDefinition().getType()) - types.addType(t.getCode()); - } - } + StructureDefinition sd = worker.fetchResource(StructureDefinition.class, ctxt); + if (sd == null) { + throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, context); + } + ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + if (ed == null) { + throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); + } + if (ed.fixedType != null) { + types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); + } else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) { + types = new TypeDetails(CollectionStatus.SINGLETON, ctxt+"#"+context); + } else { + types = new TypeDetails(CollectionStatus.SINGLETON); + for (TypeRefComponent t : ed.getDefinition().getType()) { + types.addType(t.getCode()); + } + } + } return executeType(new ExecutionTypeContext(appContext, resourceType, types, types), types, expr, true); } + private FHIRException makeException(String constName, Object... args) { + String fmt = worker.formatMessage(constName, args); + if (location != null) { + fmt = fmt + " "+worker.formatMessage(I18nConstants.FHIRPATH_LOCATION, location); + } + return new PathEngineException(fmt); + } + public TypeDetails check(Object appContext, StructureDefinition sd, String context, ExpressionNode expr) throws FHIRLexerException, PathEngineException, DefinitionException { // if context is a path that refers to a type, do that conversion now TypeDetails types; @@ -472,16 +506,18 @@ public class FHIRPathEngine { types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()); } else { ElementDefinitionMatch ed = getElementDefinition(sd, context, true); - if (ed == null) - throw new PathEngineException("Unknown context element "+context); - if (ed.fixedType != null) + if (ed == null) { + throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); + } + if (ed.fixedType != null) { types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); - else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) + } else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) { types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()+"#"+context); - else { + } else { types = new TypeDetails(CollectionStatus.SINGLETON); - for (TypeRefComponent t : ed.getDefinition().getType()) + for (TypeRefComponent t : ed.getDefinition().getType()) { types.addType(t.getCode()); + } } } @@ -533,8 +569,9 @@ public class FHIRPathEngine { */ public List evaluate(Base base, ExpressionNode ExpressionNode) throws FHIRException { List list = new ArrayList(); - if (base != null) + if (base != null) { list.add(base); + } log = new StringBuilder(); return execute(new ExecutionContext(null, base != null && base.isResource() ? base : null, base != null && base.isResource() ? base : null, base, null, base), list, ExpressionNode, true); } @@ -551,8 +588,9 @@ public class FHIRPathEngine { public List evaluate(Base base, String path) throws FHIRException { ExpressionNode exp = parse(path); List list = new ArrayList(); - if (base != null) + if (base != null) { list.add(base); + } log = new StringBuilder(); return execute(new ExecutionContext(null, base.isResource() ? base : null, base.isResource() ? base : null, base, null, base), list, exp, true); } @@ -568,8 +606,9 @@ public class FHIRPathEngine { */ public List evaluate(Object appContext, Resource focusResource, Resource rootResource, Base base, ExpressionNode ExpressionNode) throws FHIRException { List list = new ArrayList(); - if (base != null) + if (base != null) { list.add(base); + } log = new StringBuilder(); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, ExpressionNode, true); } @@ -585,8 +624,9 @@ public class FHIRPathEngine { */ public List evaluate(Object appContext, Base focusResource, Base rootResource, Base base, ExpressionNode expressionNode) throws FHIRException { List list = new ArrayList(); - if (base != null) + if (base != null) { list.add(base); + } log = new StringBuilder(); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, expressionNode, true); } @@ -603,8 +643,9 @@ public class FHIRPathEngine { public List evaluate(Object appContext, Resource focusResource, Resource rootResource, Base base, String path) throws FHIRException { ExpressionNode exp = parse(path); List list = new ArrayList(); - if (base != null) + if (base != null) { list.add(base); + } log = new StringBuilder(); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, exp, true); } @@ -686,10 +727,11 @@ public class FHIRPathEngine { StringBuilder b = new StringBuilder(); boolean first = true; for (Base item : items) { - if (first) + if (first) { first = false; - else + } else { b.append(','); + } b.append(convertToString(item)); } @@ -697,16 +739,16 @@ public class FHIRPathEngine { } public String convertToString(Base item) { - if (item.isPrimitive()) + if (item.isPrimitive()) { return item.primitiveValue(); - else if (item instanceof Quantity) { + } else if (item instanceof Quantity) { Quantity q = (Quantity) item; if (q.getSystem().equals("http://unitsofmeasure.org")) { String u = "'"+q.getCode()+"'"; return q.getValue().toPlainString()+" "+u; - } - else + } else { return item.toString(); + } } else return item.toString(); } @@ -718,39 +760,43 @@ public class FHIRPathEngine { * @return */ public boolean convertToBoolean(List items) { - if (items == null) + if (items == null) { return false; - else if (items.size() == 1 && items.get(0) instanceof BooleanType) + } else if (items.size() == 1 && items.get(0) instanceof BooleanType) { return ((BooleanType) items.get(0)).getValue(); - else if (items.size() == 1 && items.get(0).isBooleanPrimitive()) // element model + } else if (items.size() == 1 && items.get(0).isBooleanPrimitive()) { // element model return Boolean.valueOf(items.get(0).primitiveValue()); - else + } else { return items.size() > 0; + } } private void log(String name, List contents) { if (hostServices == null || !hostServices.log(name, contents)) { - if (log.length() > 0) + if (log.length() > 0) { log.append("; "); + } log.append(name); log.append(": "); boolean first = true; for (Base b : contents) { - if (first) + if (first) { first = false; - else + } else { log.append(","); + } log.append(convertToString(b)); } } } public String forLog() { - if (log.length() > 0) + if (log.length() > 0) { return " ("+log.toString()+")"; - else + } else { return ""; + } } private class ExecutionContext { @@ -783,12 +829,14 @@ public class FHIRPathEngine { return total; } public void addAlias(String name, List focus) throws FHIRException { - if (aliases == null) + if (aliases == null) { aliases = new HashMap(); - else - aliases = new HashMap(aliases); // clone it, since it's going to change - if (focus.size() > 1) - throw new FHIRException("Attempt to alias a collection, not a singleton"); + } else { + aliases = new HashMap(aliases); // clone it, since it's going to change + } + if (focus.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_ALIAS_COLLECTION); + } aliases.put(name, focus.size() == 0 ? null : focus.get(0)); } public Base getAlias(String name) { @@ -856,24 +904,26 @@ public class FHIRPathEngine { String ucum = null; if (lexer.hasToken("year", "years", "month", "months", "week", "weeks", "day", "days", "hour", "hours", "minute", "minutes", "second", "seconds", "millisecond", "milliseconds")) { String s = lexer.take(); - if (s.equals("year") || s.equals("years")) + if (s.equals("year") || s.equals("years")) { ucum = "a"; - else if (s.equals("month") || s.equals("months")) + } else if (s.equals("month") || s.equals("months")) { ucum = "mo"; - else if (s.equals("week") || s.equals("weeks")) + } else if (s.equals("week") || s.equals("weeks")) { ucum = "wk"; - else if (s.equals("day") || s.equals("days")) + } else if (s.equals("day") || s.equals("days")) { ucum = "d"; - else if (s.equals("hour") || s.equals("hours")) + } else if (s.equals("hour") || s.equals("hours")) { ucum = "h"; - else if (s.equals("minute") || s.equals("minutes")) + } else if (s.equals("minute") || s.equals("minutes")) { ucum = "min"; - else if (s.equals("second") || s.equals("seconds")) + } else if (s.equals("second") || s.equals("seconds")) { ucum = "s"; - else // (s.equals("millisecond") || s.equals("milliseconds")) + } else { // (s.equals("millisecond") || s.equals("milliseconds")) ucum = "ms"; - } else + } + } else { ucum = lexer.readConstant("units"); + } result.setConstant(new Quantity().setValue(new BigDecimal(result.getConstant().primitiveValue())).setSystem("http://unitsofmeasure.org").setCode(ucum)); } result.setEnd(lexer.getCurrentLocation()); @@ -881,28 +931,34 @@ public class FHIRPathEngine { lexer.next(); result.setKind(Kind.Group); result.setGroup(parseExpression(lexer, true)); - if (!")".equals(lexer.getCurrent())) + if (!")".equals(lexer.getCurrent())) { throw lexer.error("Found "+lexer.getCurrent()+" expecting a \")\""); + } result.setEnd(lexer.getCurrentLocation()); lexer.next(); } else { - if (!lexer.isToken() && !lexer.getCurrent().startsWith("`")) + if (!lexer.isToken() && !lexer.getCurrent().startsWith("`")) { throw lexer.error("Found "+lexer.getCurrent()+" expecting a token name"); - if (lexer.isFixedName()) + } + if (lexer.isFixedName()) { result.setName(lexer.readFixedName("Path Name")); - else + } else { result.setName(lexer.take()); + } result.setEnd(lexer.getCurrentLocation()); - if (!result.checkName()) + if (!result.checkName()) { throw lexer.error("Found "+result.getName()+" expecting a valid token name"); + } if ("(".equals(lexer.getCurrent())) { Function f = Function.fromCode(result.getName()); FunctionDetails details = null; if (f == null) { - if (hostServices != null) + if (hostServices != null) { details = hostServices.resolveFunction(result.getName()); - if (details == null) + } + if (details == null) { throw lexer.error("The name "+result.getName()+" is not a valid function name"); + } f = Function.Custom; } result.setKind(Kind.Function); @@ -910,16 +966,18 @@ public class FHIRPathEngine { lexer.next(); while (!")".equals(lexer.getCurrent())) { result.getParameters().add(parseExpression(lexer, true)); - if (",".equals(lexer.getCurrent())) + if (",".equals(lexer.getCurrent())) { lexer.next(); - else if (!")".equals(lexer.getCurrent())) + } else if (!")".equals(lexer.getCurrent())) { throw lexer.error("The token "+lexer.getCurrent()+" is not expected here - either a \",\" or a \")\" expected"); + } } result.setEnd(lexer.getCurrentLocation()); lexer.next(); checkParameters(lexer, c, result, details); - } else + } else { result.setKind(Kind.Name); + } } ExpressionNode focus = result; if ("[".equals(lexer.getCurrent())) { @@ -928,8 +986,9 @@ public class FHIRPathEngine { item.setKind(Kind.Function); item.setFunction(ExpressionNode.Function.Item); item.getParameters().add(parseExpression(lexer, true)); - if (!lexer.getCurrent().equals("]")) + if (!lexer.getCurrent().equals("]")) { throw lexer.error("The token "+lexer.getCurrent()+" is not expected here - a \"]\" expected"); + } lexer.next(); result.setInner(item); focus = item; @@ -991,8 +1050,9 @@ public class FHIRPathEngine { focus = focus.getOpNext(); } } - if (!work) + if (!work) { return start; + } // entry point: tricky ExpressionNode group; @@ -1018,8 +1078,9 @@ public class FHIRPathEngine { // focus points at the group.group do { // run until we find the end of the sequence - while (ops.contains(focus.getOperation())) + while (ops.contains(focus.getOperation())) { focus = focus.getOpNext(); + } if (focus.getOperation() != null) { group.setOperation(focus.getOperation()); group.setOpNext(focus.getOpNext()); @@ -1067,8 +1128,9 @@ public class FHIRPathEngine { return null; } else if (lexer.getCurrent().startsWith("%") || lexer.getCurrent().startsWith("@")) { return new FHIRConstant(lexer.take()); - } else + } else { throw lexer.error("Invalid Constant "+lexer.getCurrent()); + } } // procedure CheckParamCount(c : integer); @@ -1078,14 +1140,16 @@ public class FHIRPathEngine { // end; private boolean checkParamCount(FHIRLexer lexer, SourceLocation location, ExpressionNode exp, int count) throws FHIRLexerException { - if (exp.getParameters().size() != count) + if (exp.getParameters().size() != count) { throw lexer.error("The function \""+exp.getName()+"\" requires "+Integer.toString(count)+" parameters", location.toString()); + } return true; } private boolean checkParamCount(FHIRLexer lexer, SourceLocation location, ExpressionNode exp, int countMin, int countMax) throws FHIRLexerException { - if (exp.getParameters().size() < countMin || exp.getParameters().size() > countMax) + if (exp.getParameters().size() < countMin || exp.getParameters().size() > countMax) { throw lexer.error("The function \""+exp.getName()+"\" requires between "+Integer.toString(countMin)+" and "+Integer.toString(countMax)+" parameters", location.toString()); + } return true; } @@ -1184,17 +1248,20 @@ public class FHIRPathEngine { work.add(new IntegerType(0)); break; case Name: - if (atEntry && exp.getName().equals("$this")) + if (atEntry && exp.getName().equals("$this")) { work.add(context.getThisItem()); - else if (atEntry && exp.getName().equals("$total")) + } else if (atEntry && exp.getName().equals("$total")) { work.addAll(context.getTotal()); - else + } else { for (Base item : focus) { List outcome = execute(context, item, exp, atEntry); - for (Base base : outcome) - if (base != null) + for (Base base : outcome) { + if (base != null) { work.add(base); - } + } + } + } + } break; case Function: List work2 = evaluateFunction(context, focus, exp); @@ -1202,24 +1269,27 @@ public class FHIRPathEngine { break; case Constant: Base b = resolveConstant(context, exp.getConstant(), false); - if (b != null) + if (b != null) { work.add(b); + } break; case Group: work2 = execute(context, focus, exp.getGroup(), atEntry); work.addAll(work2); } - if (exp.getInner() != null) + if (exp.getInner() != null) { work = execute(context, work, exp.getInner(), false); + } if (exp.isProximal() && exp.getOperation() != null) { ExpressionNode next = exp.getOpNext(); ExpressionNode last = exp; while (next != null) { List work2 = preOperate(work, last.getOperation()); - if (work2 != null) + if (work2 != null) { work = work2; + } else if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) { work2 = executeTypeName(context, focus, next, false); work = operate(context, work, last.getOperation(), work2); @@ -1238,17 +1308,19 @@ public class FHIRPathEngine { private List executeTypeName(ExecutionContext context, List focus, ExpressionNode next, boolean atEntry) { List result = new ArrayList(); - if (next.getInner() != null) + if (next.getInner() != null) { result.add(new StringType(next.getName()+"."+next.getInner().getName())); - else + } else { result.add(new StringType(next.getName())); + } return result; } private List preOperate(List left, Operation operation) throws PathEngineException { - if (left.size() == 0) + if (left.size() == 0) { return null; + } switch (operation) { case And: return isBoolean(left, false) ? makeBoolean(false) : null; @@ -1281,18 +1353,19 @@ public class FHIRPathEngine { TypeDetails result = new TypeDetails(null); switch (exp.getKind()) { case Name: - if (atEntry && exp.getName().equals("$this")) + if (atEntry && exp.getName().equals("$this")) { result.update(context.getThisItem()); - else if (atEntry && exp.getName().equals("$total")) + } else if (atEntry && exp.getName().equals("$total")) { result.update(anything(CollectionStatus.UNORDERED)); - else if (atEntry && focus == null) + } else if (atEntry && focus == null) { result.update(executeContextType(context, exp.getName())); - else { + } else { for (String s : focus.getTypes()) { result.update(executeType(s, exp, atEntry)); } - if (result.hasNoTypes()) - throw new PathEngineException("The name '"+exp.getName()+"' is not valid for any of the possible types: "+focus.describe()); + if (result.hasNoTypes()) { + throw makeException(I18nConstants.FHIRPATH_UNKNOWN_NAME, exp.getName(), focus.describe()); + } } break; case Function: @@ -1318,10 +1391,11 @@ public class FHIRPathEngine { ExpressionNode last = exp; while (next != null) { TypeDetails work; - if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) + if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) { work = executeTypeName(context, focus, next, atEntry); - else + } else { work = executeType(context, focus, next, atEntry); + } result = operateTypes(result, last.getOperation(), work); last = next; next = next.getOpNext(); @@ -1332,15 +1406,17 @@ public class FHIRPathEngine { } private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext) throws PathEngineException { - if (!(constant instanceof FHIRConstant)) + if (!(constant instanceof FHIRConstant)) { return constant; + } FHIRConstant c = (FHIRConstant) constant; if (c.getValue().startsWith("%")) { return resolveConstant(context, c.getValue(), beforeContext); } else if (c.getValue().startsWith("@")) { return processDateConstant(context.appInfo, c.getValue().substring(1)); - } else - throw new PathEngineException("Invaild FHIR Constant "+c.getValue()); + } else { + throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, c.getValue()); + } } private Base processDateConstant(Object appInfo, String value) throws PathEngineException { @@ -1349,48 +1425,54 @@ public class FHIRPathEngine { String v = value; if (v.length() > 10) { int i = v.substring(10).indexOf("-"); - if (i == -1) + if (i == -1) { i = v.substring(10).indexOf("+"); - if (i == -1) + } + if (i == -1) { i = v.substring(10).indexOf("Z"); + } v = i == -1 ? value : v.substring(0, 10+i); } - if (v.length() > 10) + if (v.length() > 10) { return new DateTimeType(value).noExtensions(); - else + } else { return new DateType(value).noExtensions(); + } } private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext) throws PathEngineException { - if (s.equals("%sct")) + if (s.equals("%sct")) { return new StringType("http://snomed.info/sct").noExtensions(); - else if (s.equals("%loinc")) + } else if (s.equals("%loinc")) { return new StringType("http://loinc.org").noExtensions(); - else if (s.equals("%ucum")) + } else if (s.equals("%ucum")) { return new StringType("http://unitsofmeasure.org").noExtensions(); - else if (s.equals("%resource")) { - if (context.focusResource == null) - throw new PathEngineException("Cannot use %resource in this context"); + } else if (s.equals("%resource")) { + if (context.focusResource == null) { + throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); + } return context.focusResource; } else if (s.equals("%rootResource")) { - if (context.rootResource == null) - throw new PathEngineException("Cannot use %rootResource in this context"); + if (context.rootResource == null) { + throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); + } return context.rootResource; } else if (s.equals("%context")) { return context.context; - } else if (s.equals("%us-zip")) + } else if (s.equals("%us-zip")) { return new StringType("[0-9]{5}(-[0-9]{4}){0,1}").noExtensions(); - else if (s.startsWith("%`vs-")) + } else if (s.startsWith("%`vs-")) { return new StringType("http://hl7.org/fhir/ValueSet/"+s.substring(5, s.length()-1)+"").noExtensions(); - else if (s.startsWith("%`cs-")) + } else if (s.startsWith("%`cs-")) { return new StringType("http://hl7.org/fhir/"+s.substring(5, s.length()-1)+"").noExtensions(); - else if (s.startsWith("%`ext-")) + } else if (s.startsWith("%`ext-")) { return new StringType("http://hl7.org/fhir/StructureDefinition/"+s.substring(6, s.length()-1)).noExtensions(); - else if (hostServices == null) - throw new PathEngineException("Unknown fixed constant '"+s+"'"); - else + } else if (hostServices == null) { + throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); + } else { return hostServices.resolveConstant(context.appInfo, s.substring(1), beforeContext); + } } @@ -1482,13 +1564,14 @@ public class FHIRPathEngine { private List opAs(List left, List right) { List result = new ArrayList<>(); - if (right.size() != 1) + if (right.size() != 1) { return result; - else { + } else { String tn = convertToString(right); for (Base nextLeft : left) { - if (tn.equals(nextLeft.fhirType())) + if (tn.equals(nextLeft.fhirType())) { result.add(nextLeft); + } } } return result; @@ -1502,12 +1585,13 @@ public class FHIRPathEngine { result.add(new BooleanType(false).noExtensions()); else { String tn = convertToString(right); - if (left.get(0) instanceof org.hl7.fhir.r5.elementmodel.Element) + if (left.get(0) instanceof org.hl7.fhir.r5.elementmodel.Element) { result.add(new BooleanType(left.get(0).hasType(tn)).noExtensions()); - else if ((left.get(0) instanceof Element) && ((Element) left.get(0)).isDisallowExtensions()) + } else if ((left.get(0) instanceof Element) && ((Element) left.get(0)).isDisallowExtensions()) { result.add(new BooleanType(Utilities.capitalize(left.get(0).fhirType()).equals(tn) || ("System."+Utilities.capitalize(left.get(0).fhirType())).equals(tn)).noExtensions()); - else + } else { result.add(new BooleanType(left.get(0).hasType(tn)).noExtensions()); + } } return result; } @@ -1532,44 +1616,49 @@ public class FHIRPathEngine { case Implies : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Times: TypeDetails result = new TypeDetails(CollectionStatus.SINGLETON); - if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) + if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) { result.addType(TypeDetails.FP_Integer); - else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) + } else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) { result.addType(TypeDetails.FP_Decimal); + } return result; case DivideBy: result = new TypeDetails(CollectionStatus.SINGLETON); - if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) + if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) { result.addType(TypeDetails.FP_Decimal); - else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) + } else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) { result.addType(TypeDetails.FP_Decimal); + } return result; case Concatenate: result = new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); return result; case Plus: result = new TypeDetails(CollectionStatus.SINGLETON); - if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) + if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) { result.addType(TypeDetails.FP_Integer); - else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) + } else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) { result.addType(TypeDetails.FP_Decimal); - else if (left.hasType(worker, "string", "id", "code", "uri") && right.hasType(worker, "string", "id", "code", "uri")) + } else if (left.hasType(worker, "string", "id", "code", "uri") && right.hasType(worker, "string", "id", "code", "uri")) { result.addType(TypeDetails.FP_String); + } return result; case Minus: result = new TypeDetails(CollectionStatus.SINGLETON); - if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) + if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) { result.addType(TypeDetails.FP_Integer); - else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) + } else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) { result.addType(TypeDetails.FP_Decimal); + } return result; case Div: case Mod: result = new TypeDetails(CollectionStatus.SINGLETON); - if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) + if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) { result.addType(TypeDetails.FP_Integer); - else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) + } else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) { result.addType(TypeDetails.FP_Decimal); + } return result; case In: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case MemberOf: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); @@ -1581,55 +1670,61 @@ public class FHIRPathEngine { private List opEquals(List left, List right) { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); + } - if (left.size() != right.size()) + if (left.size() != right.size()) { return makeBoolean(false); + } boolean res = true; boolean nil = false; for (int i = 0; i < left.size(); i++) { Boolean eq = doEquals(left.get(i), right.get(i)); - if (eq == null) + if (eq == null) { nil = true; - else if (eq == false) { + } else if (eq == false) { res = false; break; } } - if (!res) + if (!res) { return makeBoolean(res); - else if (nil) + } else if (nil) { return new ArrayList(); - else + } else { return makeBoolean(res); + } } private List opNotEquals(List left, List right) { - if (!legacyMode && (left.size() == 0 || right.size() == 0)) + if (!legacyMode && (left.size() == 0 || right.size() == 0)) { return new ArrayList(); + } - if (left.size() != right.size()) + if (left.size() != right.size()) { return makeBoolean(true); + } boolean res = true; boolean nil = false; for (int i = 0; i < left.size(); i++) { Boolean eq = doEquals(left.get(i), right.get(i)); - if (eq == null) + if (eq == null) { nil = true; - else if (eq == true) { + } else if (eq == true) { res = false; break; } } - if (!res) + if (!res) { return makeBoolean(res); - else if (nil) + } else if (nil) { return new ArrayList(); - else + } else { return makeBoolean(res); + } } private String removeTrailingZeros(String s) { @@ -1642,11 +1737,11 @@ public class FHIRPathEngine { if (s.charAt(i) == '.') { i--; dot = true; - } - else if (!dot && s.charAt(i) == '0') + } else if (!dot && s.charAt(i) == '0') { i--; - else + } else { done = true; + } } return s.substring(0, i+1); } @@ -1662,32 +1757,39 @@ public class FHIRPathEngine { } private Boolean doEquals(Base left, Base right) { - if (left instanceof Quantity && right instanceof Quantity) + if (left instanceof Quantity && right instanceof Quantity) { return qtyEqual((Quantity) left, (Quantity) right); - else if (left.isDateTime() && right.isDateTime()) { + } else if (left.isDateTime() && right.isDateTime()) { return compareDates(left.dateTimeValue(), right.dateTimeValue()); - } else if (left instanceof DecimalType || right instanceof DecimalType) + } else if (left instanceof DecimalType || right instanceof DecimalType) { return decEqual(left.primitiveValue(), right.primitiveValue()); - else if (left.isPrimitive() && right.isPrimitive()) + } else if (left.isPrimitive() && right.isPrimitive()) { return Base.equals(left.primitiveValue(), right.primitiveValue()); - else + } else { return Base.compareDeep(left, right, false); + } } private boolean doEquivalent(Base left, Base right) throws PathEngineException { - if (left instanceof Quantity && right instanceof Quantity) + if (left instanceof Quantity && right instanceof Quantity) { return qtyEquivalent((Quantity) left, (Quantity) right); - if (left.hasType("integer") && right.hasType("integer")) + } + if (left.hasType("integer") && right.hasType("integer")) { return doEquals(left, right); - if (left.hasType("boolean") && right.hasType("boolean")) + } + if (left.hasType("boolean") && right.hasType("boolean")) { return doEquals(left, right); - if (left.hasType("integer", "decimal", "unsignedInt", "positiveInt") && right.hasType("integer", "decimal", "unsignedInt", "positiveInt")) + } + if (left.hasType("integer", "decimal", "unsignedInt", "positiveInt") && right.hasType("integer", "decimal", "unsignedInt", "positiveInt")) { return Utilities.equivalentNumber(left.primitiveValue(), right.primitiveValue()); - if (left.hasType("date", "dateTime", "time", "instant") && right.hasType("date", "dateTime", "time", "instant")) + } + if (left.hasType("date", "dateTime", "time", "instant") && right.hasType("date", "dateTime", "time", "instant")) { return compareDateTimeElements(left, right, true) == 0; - if (left.hasType(FHIR_TYPES_STRING) && right.hasType(FHIR_TYPES_STRING)) + } + if (left.hasType(FHIR_TYPES_STRING) && right.hasType(FHIR_TYPES_STRING)) { return Utilities.equivalent(convertToString(left), convertToString(right)); + } throw new PathEngineException(String.format("Unable to determine equivalence between %s and %s", left.fhirType(), right.fhirType())); } @@ -1696,15 +1798,17 @@ public class FHIRPathEngine { if (worker.getUcumService() != null) { DecimalType dl = qtyToCanonical(left); DecimalType dr = qtyToCanonical(right); - if (dl != null && dr != null) + if (dl != null && dr != null) { return doEquals(dl, dr); + } } return left.equals(right); } private DecimalType qtyToCanonical(Quantity q) { - if (!"http://unitsofmeasure.org".equals(q.getSystem())) + if (!"http://unitsofmeasure.org".equals(q.getSystem())) { return null; + } try { Pair p = new Pair(new Decimal(q.getValue().toPlainString()), q.getCode()); Pair c = worker.getUcumService().getCanonicalForm(p); @@ -1720,8 +1824,9 @@ public class FHIRPathEngine { private Pair qtyToPair(Quantity q) { - if (!"http://unitsofmeasure.org".equals(q.getSystem())) + if (!"http://unitsofmeasure.org".equals(q.getSystem())) { return null; + } try { return new Pair(new Decimal(q.getValue().toPlainString()), q.getCode()); } catch (UcumException e) { @@ -1734,8 +1839,9 @@ public class FHIRPathEngine { if (worker.getUcumService() != null) { DecimalType dl = qtyToCanonical(left); DecimalType dr = qtyToCanonical(right); - if (dl != null && dr != null) + if (dl != null && dr != null) { return doEquivalent(dl, dr); + } } return left.equals(right); } @@ -1743,8 +1849,9 @@ public class FHIRPathEngine { private List opEquivalent(List left, List right) throws PathEngineException { - if (left.size() != right.size()) + if (left.size() != right.size()) { return makeBoolean(false); + } boolean res = true; for (int i = 0; i < left.size(); i++) { @@ -1764,8 +1871,9 @@ public class FHIRPathEngine { } private List opNotEquivalent(List left, List right) throws PathEngineException { - if (left.size() != right.size()) + if (left.size() != right.size()) { return makeBoolean(true); + } boolean res = true; for (int i = 0; i < left.size(); i++) { @@ -1793,25 +1901,26 @@ public class FHIRPathEngine { if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { Base l = left.get(0); Base r = right.get(0); - if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) + if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0); - else if ((l.hasType("integer") || l.hasType("decimal")) && (r.hasType("integer") || r.hasType("decimal"))) + } else if ((l.hasType("integer") || l.hasType("decimal")) && (r.hasType("integer") || r.hasType("decimal"))) { return makeBoolean(new Double(l.primitiveValue()) < new Double(r.primitiveValue())); - else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) + } else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) { return makeBoolean(compareDateTimeElements(l, r, false) < 0); - else if ((l.hasType("time")) && (r.hasType("time"))) + } else if ((l.hasType("time")) && (r.hasType("time"))) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0); - else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + } else { + throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("code"); List rUnit = right.get(0).listChildrenByName("code"); if (Base.compareDeep(lUnit, rUnit, true)) { return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); } else { - if (worker.getUcumService() == null) + if (worker.getUcumService() == null) { return makeBoolean(false); - else { + } else { List dl = new ArrayList(); dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); @@ -1829,25 +1938,26 @@ public class FHIRPathEngine { if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { Base l = left.get(0); Base r = right.get(0); - if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) + if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0); - else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) + } else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) { return makeBoolean(new Double(l.primitiveValue()) > new Double(r.primitiveValue())); - else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) + } else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) { return makeBoolean(compareDateTimeElements(l, r, false) > 0); - else if ((l.hasType("time")) && (r.hasType("time"))) + } else if ((l.hasType("time")) && (r.hasType("time"))) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0); - else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + } else { + throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); } else { - if (worker.getUcumService() == null) + if (worker.getUcumService() == null) { return makeBoolean(false); - else { + } else { List dl = new ArrayList(); dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); @@ -1860,21 +1970,23 @@ public class FHIRPathEngine { } private List opLessOrEqual(List left, List right) throws FHIRException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); + } if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { Base l = left.get(0); Base r = right.get(0); - if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) + if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0); - else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) + } else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) { return makeBoolean(new Double(l.primitiveValue()) <= new Double(r.primitiveValue())); - else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) + } else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) { return makeBoolean(compareDateTimeElements(l, r, false) <= 0); - else if ((l.hasType("time")) && (r.hasType("time"))) + } else if ((l.hasType("time")) && (r.hasType("time"))) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0); - else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + } else { + throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnits = left.get(0).listChildrenByName("unit"); String lunit = lUnits.size() == 1 ? lUnits.get(0).primitiveValue() : null; @@ -1883,9 +1995,9 @@ public class FHIRPathEngine { if ((lunit == null && runit == null) || lunit.equals(runit)) { return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); } else { - if (worker.getUcumService() == null) + if (worker.getUcumService() == null) { return makeBoolean(false); - else { + } else { List dl = new ArrayList(); dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); @@ -1898,30 +2010,32 @@ public class FHIRPathEngine { } private List opGreaterOrEqual(List left, List right) throws FHIRException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); + } if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { Base l = left.get(0); Base r = right.get(0); - if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) + if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0); - else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) + } else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) { return makeBoolean(new Double(l.primitiveValue()) >= new Double(r.primitiveValue())); - else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) + } else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) { return makeBoolean(compareDateTimeElements(l, r, false) >= 0); - else if ((l.hasType("time")) && (r.hasType("time"))) + } else if ((l.hasType("time")) && (r.hasType("time"))) { return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0); - else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + } else { + throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); } else { - if (worker.getUcumService() == null) + if (worker.getUcumService() == null) { return makeBoolean(false); - else { + } else { List dl = new ArrayList(); dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); @@ -1939,14 +2053,17 @@ public class FHIRPathEngine { if (vs != null) { for (Base l : left) { if (Utilities.existsInList(l.fhirType(), "code", "string", "uri")) { - if (worker.validateCode(terminologyServiceOptions , TypeConvertor.castToCoding(l), vs).isOk()) + if (worker.validateCode(terminologyServiceOptions , TypeConvertor.castToCoding(l), vs).isOk()) { ans = true; + } } else if (l.fhirType().equals("Coding")) { - if (worker.validateCode(terminologyServiceOptions, TypeConvertor.castToCoding(l), vs).isOk()) + if (worker.validateCode(terminologyServiceOptions, TypeConvertor.castToCoding(l), vs).isOk()) { ans = true; + } } else if (l.fhirType().equals("CodeableConcept")) { - if (worker.validateCode(terminologyServiceOptions, TypeConvertor.castToCodeableConcept(l), vs).isOk()) + if (worker.validateCode(terminologyServiceOptions, TypeConvertor.castToCodeableConcept(l), vs).isOk()) { ans = true; + } } else { // System.out.println("unknown type in opMemberOf: "+l.fhirType()); } @@ -1956,10 +2073,12 @@ public class FHIRPathEngine { } private List opIn(List left, List right) throws FHIRException { - if (left.size() == 0) + if (left.size() == 0) { return new ArrayList(); - if (right.size() == 0) + } + if (right.size() == 0) { return makeBoolean(false); + } boolean ans = true; for (Base l : left) { boolean f = false; @@ -1979,8 +2098,9 @@ public class FHIRPathEngine { } private List opContains(List left, List right) { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); + } boolean ans = true; for (Base r : right) { boolean f = false; @@ -2000,52 +2120,63 @@ public class FHIRPathEngine { } private List opPlus(List left, List right) throws PathEngineException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); - if (left.size() > 1) - throw new PathEngineException("Error performing +: left operand has more than one value"); - if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType())); - if (right.size() > 1) - throw new PathEngineException("Error performing +: right operand has more than one value"); - if (!right.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing +: right operand has the wrong type (%s)", right.get(0).fhirType())); + } + if (left.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "+"); + } + if (!left.get(0).isPrimitive()) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "+", left.get(0).fhirType()); + } + if (right.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "+"); + } + if (!right.get(0).isPrimitive()) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "+", right.get(0).fhirType()); + } List result = new ArrayList(); Base l = left.get(0); Base r = right.get(0); - if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) + if (l.hasType(FHIR_TYPES_STRING) && r.hasType(FHIR_TYPES_STRING)) { result.add(new StringType(l.primitiveValue() + r.primitiveValue())); - else if (l.hasType("integer") && r.hasType("integer")) + } else if (l.hasType("integer") && r.hasType("integer")) { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) + Integer.parseInt(r.primitiveValue()))); - else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) + } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { result.add(new DecimalType(new BigDecimal(l.primitiveValue()).add(new BigDecimal(r.primitiveValue())))); - else - throw new PathEngineException(String.format("Error performing +: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + } else { + throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "+", left.get(0).fhirType(), right.get(0).fhirType()); + } return result; } private List opTimes(List left, List right) throws PathEngineException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); - if (left.size() > 1) - throw new PathEngineException("Error performing *: left operand has more than one value"); - if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType())); - if (right.size() > 1) - throw new PathEngineException("Error performing *: right operand has more than one value"); - if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing *: right operand has the wrong type (%s)", right.get(0).fhirType())); + } + if (left.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "*"); + } + if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "*", left.get(0).fhirType()); + } + if (right.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "*"); + } + if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "*", right.get(0).fhirType()); + } List result = new ArrayList(); Base l = left.get(0); Base r = right.get(0); - if (l.hasType("integer") && r.hasType("integer")) + if (l.hasType("integer") && r.hasType("integer")) { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) * Integer.parseInt(r.primitiveValue()))); - else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) + } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { result.add(new DecimalType(new BigDecimal(l.primitiveValue()).multiply(new BigDecimal(r.primitiveValue())))); - else if (l instanceof Quantity && r instanceof Quantity && worker.getUcumService() != null) { + } else if (l instanceof Quantity && r instanceof Quantity && worker.getUcumService() != null) { Pair pl = qtyToPair((Quantity) l); Pair pr = qtyToPair((Quantity) r); Pair p; @@ -2055,21 +2186,26 @@ public class FHIRPathEngine { } catch (UcumException e) { throw new PathEngineException(e.getMessage(), e); } - } else - throw new PathEngineException(String.format("Error performing *: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + } else { + throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "*", left.get(0).fhirType(), right.get(0).fhirType()); + } return result; } private List opConcatenate(List left, List right) throws PathEngineException { - if (left.size() > 1) - throw new PathEngineException("Error performing &: left operand has more than one value"); - if (left.size() > 0 && !left.get(0).hasType(FHIR_TYPES_STRING)) - throw new PathEngineException(String.format("Error performing &: left operand has the wrong type (%s)", left.get(0).fhirType())); - if (right.size() > 1) - throw new PathEngineException("Error performing &: right operand has more than one value"); - if (right.size() > 0 && !right.get(0).hasType(FHIR_TYPES_STRING)) - throw new PathEngineException(String.format("Error performing &: right operand has the wrong type (%s)", right.get(0).fhirType())); + if (left.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "&"); + } + if (left.size() > 0 && !left.get(0).hasType(FHIR_TYPES_STRING)) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "&", left.get(0).fhirType()); + } + if (right.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "&"); + } + if (right.size() > 0 && !right.get(0).hasType(FHIR_TYPES_STRING)) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "&", right.get(0).fhirType()); + } List result = new ArrayList(); String l = left.size() == 0 ? "" : left.get(0).primitiveValue(); @@ -2081,12 +2217,14 @@ public class FHIRPathEngine { private List opUnion(List left, List right) { List result = new ArrayList(); for (Base item : left) { - if (!doContains(result, item)) + if (!doContains(result, item)) { result.add(item); + } } for (Base item : right) { - if (!doContains(result, item)) + if (!doContains(result, item)) { result.add(item); + } } return result; } @@ -2094,8 +2232,9 @@ public class FHIRPathEngine { private boolean doContains(List list, Base item) { for (Base test : list) { Boolean eq = doEquals(test, item); - if (eq != null && eq == true) + if (eq != null && eq == true) { return true; + } } return false; } @@ -2107,10 +2246,11 @@ public class FHIRPathEngine { switch (l) { case False: return makeBoolean(false); case Null: - if (r == Equality.False) + if (r == Equality.False) { return makeBoolean(false); - else + } else { return makeNull(); + } case True: switch (r) { case False: return makeBoolean(false); @@ -2131,10 +2271,11 @@ public class FHIRPathEngine { switch (l) { case True: return makeBoolean(true); case Null: - if (r == Equality.True) + if (r == Equality.True) { return makeBoolean(true); - else + } else { return makeNull(); + } case False: switch (r) { case False: return makeBoolean(false); @@ -2169,11 +2310,11 @@ public class FHIRPathEngine { private List opImplies(List left, List right) throws PathEngineException { Equality eq = asBool(left); - if (eq == Equality.False) + if (eq == Equality.False) { return makeBoolean(true); - else if (right.size() == 0) + } else if (right.size() == 0) { return makeNull(); - else switch (asBool(right)) { + } else switch (asBool(right)) { case False: return eq == Equality.Null ? makeNull() : makeBoolean(false); case Null: return makeNull(); case True: return makeBoolean(true); @@ -2183,41 +2324,52 @@ public class FHIRPathEngine { private List opMinus(List left, List right) throws PathEngineException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); - if (left.size() > 1) - throw new PathEngineException("Error performing -: left operand has more than one value"); - if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType())); - if (right.size() > 1) - throw new PathEngineException("Error performing -: right operand has more than one value"); - if (!right.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing -: right operand has the wrong type (%s)", right.get(0).fhirType())); + } + if (left.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "-"); + } + if (!left.get(0).isPrimitive()) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "-", left.get(0).fhirType()); + } + if (right.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "-"); + } + if (!right.get(0).isPrimitive()) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "-", right.get(0).fhirType()); + } List result = new ArrayList(); Base l = left.get(0); Base r = right.get(0); - if (l.hasType("integer") && r.hasType("integer")) + if (l.hasType("integer") && r.hasType("integer")) { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) - Integer.parseInt(r.primitiveValue()))); - else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) + } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { result.add(new DecimalType(new BigDecimal(l.primitiveValue()).subtract(new BigDecimal(r.primitiveValue())))); - else - throw new PathEngineException(String.format("Error performing -: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + } else { + throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "-", left.get(0).fhirType(), right.get(0).fhirType()); + } return result; } private List opDivideBy(List left, List right) throws PathEngineException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); - if (left.size() > 1) - throw new PathEngineException("Error performing /: left operand has more than one value"); - if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType())); - if (right.size() > 1) - throw new PathEngineException("Error performing /: right operand has more than one value"); - if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing /: right operand has the wrong type (%s)", right.get(0).fhirType())); + } + if (left.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "/"); + } + if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "/", left.get(0).fhirType()); + } + if (right.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "/"); + } + if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "/", right.get(0).fhirType()); + } List result = new ArrayList(); Base l = left.get(0); @@ -2242,30 +2394,36 @@ public class FHIRPathEngine { } catch (UcumException e) { throw new PathEngineException(e.getMessage(), e); } - } else - throw new PathEngineException(String.format("Error performing /: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + } else { + throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "/", left.get(0).fhirType(), right.get(0).fhirType()); + } return result; } private List opDiv(List left, List right) throws PathEngineException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); - if (left.size() > 1) - throw new PathEngineException("Error performing div: left operand has more than one value"); - if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing div: left operand has the wrong type (%s)", left.get(0).fhirType())); - if (right.size() > 1) - throw new PathEngineException("Error performing div: right operand has more than one value"); - if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing div: right operand has the wrong type (%s)", right.get(0).fhirType())); + } + if (left.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "div"); + } + if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "div", left.get(0).fhirType()); + } + if (right.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "div"); + } + if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "div", right.get(0).fhirType()); + } List result = new ArrayList(); Base l = left.get(0); Base r = right.get(0); - if (l.hasType("integer") && r.hasType("integer")) + if (l.hasType("integer") && r.hasType("integer")) { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) / Integer.parseInt(r.primitiveValue()))); - else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { + } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { Decimal d1; try { d1 = new Decimal(l.primitiveValue()); @@ -2274,31 +2432,35 @@ public class FHIRPathEngine { } catch (UcumException e) { throw new PathEngineException(e); } + } else { + throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "div", left.get(0).fhirType(), right.get(0).fhirType()); } - else - throw new PathEngineException(String.format("Error performing div: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); return result; } private List opMod(List left, List right) throws PathEngineException { - if (left.size() == 0 || right.size() == 0) + if (left.size() == 0 || right.size() == 0) { return new ArrayList(); - if (left.size() > 1) - throw new PathEngineException("Error performing mod: left operand has more than one value"); - if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing mod: left operand has the wrong type (%s)", left.get(0).fhirType())); - if (right.size() > 1) - throw new PathEngineException("Error performing mod: right operand has more than one value"); - if (!right.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing mod: right operand has the wrong type (%s)", right.get(0).fhirType())); + } if (left.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "mod"); + } + if (!left.get(0).isPrimitive()) { + throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "mod", left.get(0).fhirType()); + } + if (right.size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "mod"); + } + if (!right.get(0).isPrimitive()) { + throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "mod", right.get(0).fhirType()); + } List result = new ArrayList(); Base l = left.get(0); Base r = right.get(0); - if (l.hasType("integer") && r.hasType("integer")) + if (l.hasType("integer") && r.hasType("integer")) { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) % Integer.parseInt(r.primitiveValue()))); - else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { + } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { Decimal d1; try { d1 = new Decimal(l.primitiveValue()); @@ -2307,64 +2469,69 @@ public class FHIRPathEngine { } catch (UcumException e) { throw new PathEngineException(e); } + } else { + throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "mod", left.get(0).fhirType(), right.get(0).fhirType()); } - else - throw new PathEngineException(String.format("Error performing mod: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); return result; } private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant) throws PathEngineException { - if (constant instanceof BooleanType) + if (constant instanceof BooleanType) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); - else if (constant instanceof IntegerType) + } else if (constant instanceof IntegerType) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); - else if (constant instanceof DecimalType) + } else if (constant instanceof DecimalType) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); - else if (constant instanceof Quantity) + } else if (constant instanceof Quantity) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); - else if (constant instanceof FHIRConstant) + } else if (constant instanceof FHIRConstant) { return resolveConstantType(context, ((FHIRConstant) constant).getValue()); - else + } else { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); + } } private TypeDetails resolveConstantType(ExecutionTypeContext context, String s) throws PathEngineException { if (s.startsWith("@")) { - if (s.startsWith("@T")) + if (s.startsWith("@T")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); - else + } else { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); - } else if (s.equals("%sct")) + } + } else if (s.equals("%sct")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (s.equals("%loinc")) + } else if (s.equals("%loinc")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (s.equals("%ucum")) + } else if (s.equals("%ucum")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (s.equals("%resource")) { - if (context.resource == null) - throw new PathEngineException("%resource cannot be used in this context"); + } else if (s.equals("%resource")) { + if (context.resource == null) { + throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); + } return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%rootResource")) { - if (context.resource == null) - throw new PathEngineException("%rootResource cannot be used in this context"); + if (context.resource == null) { + throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); + } return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%context")) { return context.context; - } else if (s.equals("%map-codes")) + } else if (s.equals("%map-codes")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (s.equals("%us-zip")) + } else if (s.equals("%us-zip")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (s.startsWith("%`vs-")) + } else if (s.startsWith("%`vs-")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (s.startsWith("%`cs-")) + } else if (s.startsWith("%`cs-")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (s.startsWith("%`ext-")) + } else if (s.startsWith("%`ext-")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - else if (hostServices == null) - throw new PathEngineException("Unknown fixed constant type for '"+s+"'"); - else + } else if (hostServices == null) { + throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); + } else { return hostServices.resolveConstantType(context.appInfo, s); + } } private List execute(ExecutionContext context, Base item, ExpressionNode exp, boolean atEntry) throws FHIRException { @@ -2393,8 +2560,9 @@ public class FHIRPathEngine { sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); } } - } else + } else { getChildrenByName(item, exp.getName(), result); + } if (atEntry && context.appInfo != null && hostServices != null && result.isEmpty()) { // well, we didn't get a match on the name - we'll see if the name matches a constant known by the context. // (if the name does match, and the user wants to get the constant value, they'll have to try harder... @@ -2412,14 +2580,16 @@ public class FHIRPathEngine { private TypeDetails executeContextType(ExecutionTypeContext context, String name) throws PathEngineException, DefinitionException { - if (hostServices == null) - throw new PathEngineException("Unable to resolve context reference since no host services are provided"); + if (hostServices == null) { + throw makeException(I18nConstants.FHIRPATH_HO_HOST_SERVICES, "Context Reference"); + } return hostServices.resolveConstantType(context.appInfo, name); } private TypeDetails executeType(String type, ExpressionNode exp, boolean atEntry) throws PathEngineException, DefinitionException { - if (atEntry && Character.isUpperCase(exp.getName().charAt(0)) && hashTail(type).equals(exp.getName())) // special case for start up + if (atEntry && Character.isUpperCase(exp.getName().charAt(0)) && hashTail(type).equals(exp.getName())) { // special case for start up return new TypeDetails(CollectionStatus.SINGLETON, type); + } TypeDetails result = new TypeDetails(null); getChildTypesByName(type, exp.getName(), result); return result; @@ -2434,15 +2604,17 @@ public class FHIRPathEngine { @SuppressWarnings("unchecked") private TypeDetails evaluateFunctionType(ExecutionTypeContext context, TypeDetails focus, ExpressionNode exp) throws PathEngineException, DefinitionException { List paramTypes = new ArrayList(); - if (exp.getFunction() == Function.Is || exp.getFunction() == Function.As || exp.getFunction() == Function.OfType) + if (exp.getFunction() == Function.Is || exp.getFunction() == Function.As || exp.getFunction() == Function.OfType) { paramTypes.add(new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); - else + } else { for (ExpressionNode expr : exp.getParameters()) { - if (exp.getFunction() == Function.Where || exp.getFunction() == Function.All || exp.getFunction() == Function.Select || exp.getFunction() == Function.Repeat || exp.getFunction() == Function.Aggregate) + if (exp.getFunction() == Function.Where || exp.getFunction() == Function.All || exp.getFunction() == Function.Select || exp.getFunction() == Function.Repeat || exp.getFunction() == Function.Aggregate) { paramTypes.add(executeType(changeThis(context, focus), focus, expr, true)); - else + } else { paramTypes.add(executeType(context, focus, expr, true)); + } } + } switch (exp.getFunction()) { case Empty : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); @@ -2496,12 +2668,13 @@ public class FHIRPathEngine { s = s || pt.isSystemType(); c = c || !pt.isSystemType(); } - if (s && c) + if (s && c) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_SimpleTypeInfo, TypeDetails.FP_ClassInfo); - else if (s) + } else if (s) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_SimpleTypeInfo); - else + } else { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_ClassInfo); + } } case Is : { checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); @@ -2546,8 +2719,9 @@ public class FHIRPathEngine { case Iif : { TypeDetails types = new TypeDetails(null); types.update(paramTypes.get(0)); - if (paramTypes.size() > 1) + if (paramTypes.size() > 1) { types.update(paramTypes.get(1)); + } return types; } case Lower : { @@ -2731,53 +2905,62 @@ public class FHIRPathEngine { private void checkParamTypes(String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { int i = 0; for (TypeDetails pt : typeSet) { - if (i == paramTypes.size()) + if (i == paramTypes.size()) { return; + } TypeDetails actual = paramTypes.get(i); i++; for (String a : actual.getTypes()) { - if (!pt.hasType(worker, a)) - throw new PathEngineException("The parameter type '"+a+"' is not legal for "+funcName+" parameter "+Integer.toString(i)+". expecting "+pt.toString()); + if (!pt.hasType(worker, a)) { + throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, funcName, i, a, pt.toString()); + } } } } private void checkOrdered(TypeDetails focus, String name) throws PathEngineException { - if (focus.getCollectionStatus() == CollectionStatus.UNORDERED) - throw new PathEngineException("The function '"+name+"'() can only be used on ordered collections"); + if (focus.getCollectionStatus() == CollectionStatus.UNORDERED) { + throw makeException(I18nConstants.FHIRPATH_ORDERED_ONLY, name); + } } private void checkContextReference(TypeDetails focus, String name) throws PathEngineException { - if (!focus.hasType(worker, "string") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Reference") && !focus.hasType(worker, "canonical")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, canonical, Reference"); + if (!focus.hasType(worker, "string") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Reference") && !focus.hasType(worker, "canonical")) { + throw makeException(I18nConstants.FHIRPATH_REFERENCE_ONLY, name, focus.describe()); + } } private void checkContextCoded(TypeDetails focus, String name) throws PathEngineException { - if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Coding") && !focus.hasType(worker, "CodeableConcept")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, code, uri, Coding, CodeableConcept"); + if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Coding") && !focus.hasType(worker, "CodeableConcept")) { + throw makeException(I18nConstants.FHIRPATH_CODED_ONLY, name, focus.describe()); + } } private void checkContextString(TypeDetails focus, String name) throws PathEngineException { - if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, code, id, but found "+focus.describe()); + if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) { + throw makeException(I18nConstants.FHIRPATH_STRING_ONLY, name, focus.describe()); + } } private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty) throws PathEngineException { if (canQty) { - if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) - throw new PathEngineException("The function '"+name+"'() can only be used on a Quantity or on "+primitiveTypes.toString()); - } else if (!focus.hasType(primitiveTypes)) - throw new PathEngineException("The function '"+name+"'() can only be used on "+primitiveTypes.toString()); + if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) { + throw makeException(I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString()); + } + } else if (!focus.hasType(primitiveTypes)) { + throw makeException(I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString()); + } } private TypeDetails childTypes(TypeDetails focus, String mask) throws PathEngineException, DefinitionException { TypeDetails result = new TypeDetails(CollectionStatus.UNORDERED); - for (String f : focus.getTypes()) + for (String f : focus.getTypes()) { getChildTypesByName(f, mask, result); + } return result; } @@ -2873,8 +3056,9 @@ public class FHIRPathEngine { case ConformsTo : return funcConformsTo(context, focus, exp); case Custom: { List> params = new ArrayList>(); - for (ExpressionNode p : exp.getParameters()) + for (ExpressionNode p : exp.getParameters()) { params.add(execute(context, focus, p, true)); + } return hostServices.executeFunction(context.appInfo, exp.getName(), params); } default: @@ -2884,26 +3068,25 @@ public class FHIRPathEngine { private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); public static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars); + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars); } public static byte[] hexStringToByteArray(String s) { - int len = s.length(); - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) - + Character.digit(s.charAt(i+1), 16)); - } - return data; - } - - private List funcEncode(ExecutionContext context, List focus, ExpressionNode exp) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); + } + return data; + } + + private List funcEncode(ExecutionContext context, List focus, ExpressionNode exp) { List nl = execute(context, focus, exp.getParameters().get(0), true); String param = nl.get(0).primitiveValue(); @@ -3028,8 +3211,9 @@ public class FHIRPathEngine { String name = nl.get(0).primitiveValue(); List res = new ArrayList(); Base b = context.getAlias(name); - if (b != null) + if (b != null) { res.add(b); + } return res; } @@ -3139,8 +3323,9 @@ public class FHIRPathEngine { private List funcChildren(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List result = new ArrayList(); - for (Base b : focus) + for (Base b : focus) { getChildrenByName(b, "*", result); + } return result; } @@ -3150,27 +3335,16 @@ public class FHIRPathEngine { if (focus.size() == 1) { String f = convertToString(focus.get(0)); - - if (!Utilities.noString(f)) { - - if (exp.getParameters().size() == 2) { - - String t = convertToString(execute(context, focus, exp.getParameters().get(0), true)); - String r = convertToString(execute(context, focus, exp.getParameters().get(1), true)); - - String n = f.replace(t, r); - result.add(new StringType(n)); - } - else { - throw new PathEngineException(String.format("funcReplace() : checking for 2 arguments (pattern, substitution) but found %d items", exp.getParameters().size())); - } + if (Utilities.noString(f)) { + result.add(new StringType("")); + } else { + String t = convertToString(execute(context, focus, exp.getParameters().get(0), true)); + String r = convertToString(execute(context, focus, exp.getParameters().get(1), true)); + String n = f.replace(t, r); + result.add(new StringType(n)); } - else { - throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found empty item")); - } - } - else { - throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found %d items", focus.size())); + } else { + throw makeException(I18nConstants.FHIRPATH_NO_COLLECTION, "replace", focus.size()); } return result; } @@ -3181,10 +3355,11 @@ public class FHIRPathEngine { String regex = convertToString(execute(context, focus, exp.getParameters().get(0), true)); String repl = convertToString(execute(context, focus, exp.getParameters().get(1), true)); - if (focus.size() == 1 && !Utilities.noString(regex)) + if (focus.size() == 1 && !Utilities.noString(regex)) { result.add(new StringType(convertToString(focus.get(0)).replaceAll(regex, repl)).noExtensions()); - else + } else { result.add(new StringType(convertToString(focus.get(0))).noExtensions()); + } return result; } @@ -3193,15 +3368,16 @@ public class FHIRPathEngine { List result = new ArrayList(); String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true)); - if (focus.size() == 0) + if (focus.size() == 0) { result.add(new BooleanType(false).noExtensions()); - else if (Utilities.noString(sw)) + } else if (Utilities.noString(sw)) { result.add(new BooleanType(true).noExtensions()); - else { - if (focus.size() == 1 && !Utilities.noString(sw)) + } else { + if (focus.size() == 1 && !Utilities.noString(sw)) { result.add(new BooleanType(convertToString(focus.get(0)).endsWith(sw)).noExtensions()); - else + } else { result.add(new BooleanType(false).noExtensions()); + } } return result; } @@ -3216,24 +3392,27 @@ public class FHIRPathEngine { private List funcToBoolean(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); if (focus.size() == 1) { - if (focus.get(0) instanceof BooleanType) + if (focus.get(0) instanceof BooleanType) { result.add(focus.get(0)); - else if (focus.get(0) instanceof IntegerType) { + } else if (focus.get(0) instanceof IntegerType) { int i = Integer.parseInt(focus.get(0).primitiveValue()); - if (i == 0) + if (i == 0) { result.add(new BooleanType(false).noExtensions()); - else if (i == 1) + } else if (i == 1) { result.add(new BooleanType(true).noExtensions()); + } } else if (focus.get(0) instanceof DecimalType) { - if (((DecimalType) focus.get(0)).getValue().compareTo(BigDecimal.ZERO) == 0) + if (((DecimalType) focus.get(0)).getValue().compareTo(BigDecimal.ZERO) == 0) { result.add(new BooleanType(false).noExtensions()); - else if (((DecimalType) focus.get(0)).getValue().compareTo(BigDecimal.ONE) == 0) + } else if (((DecimalType) focus.get(0)).getValue().compareTo(BigDecimal.ONE) == 0) { result.add(new BooleanType(true).noExtensions()); + } } else if (focus.get(0) instanceof StringType) { - if ("true".equalsIgnoreCase(focus.get(0).primitiveValue())) + if ("true".equalsIgnoreCase(focus.get(0).primitiveValue())) { result.add(new BooleanType(true).noExtensions()); - else if ("false".equalsIgnoreCase(focus.get(0).primitiveValue())) + } else if ("false".equalsIgnoreCase(focus.get(0).primitiveValue())) { result.add(new BooleanType(false).noExtensions()); + } } } return result; @@ -3242,12 +3421,13 @@ public class FHIRPathEngine { private List funcToQuantity(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); if (focus.size() == 1) { - if (focus.get(0) instanceof Quantity) + if (focus.get(0) instanceof Quantity) { result.add(focus.get(0)); - else if (focus.get(0) instanceof StringType) { + } else if (focus.get(0) instanceof StringType) { Quantity q = parseQuantityString(focus.get(0).primitiveValue()); - if (q != null) + if (q != null) { result.add(q.noExtensions()); + } } else if (focus.get(0) instanceof IntegerType) { result.add(new Quantity().setValue(new BigDecimal(focus.get(0).primitiveValue())).setSystem("http://unitsofmeasure.org").setCode("1").noExtensions()); } else if (focus.get(0) instanceof DecimalType) { @@ -3261,26 +3441,29 @@ public class FHIRPathEngine { // List result = new ArrayList(); // result.add(new BooleanType(convertToBoolean(focus))); // return result; - throw new NotImplementedException("funcToDateTime is not implemented"); + throw makeException(I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toDateTime"); } private List funcToTime(ExecutionContext context, List focus, ExpressionNode exp) { // List result = new ArrayList(); // result.add(new BooleanType(convertToBoolean(focus))); // return result; - throw new NotImplementedException("funcToTime is not implemented"); + throw makeException(I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toTime"); } private List funcToDecimal(ExecutionContext context, List focus, ExpressionNode exp) { String s = convertToString(focus); List result = new ArrayList(); - if (Utilities.isDecimal(s, true)) + if (Utilities.isDecimal(s, true)) { result.add(new DecimalType(s).noExtensions()); - if ("true".equals(s)) + } + if ("true".equals(s)) { result.add(new DecimalType(1).noExtensions()); - if ("false".equals(s)) + } + if ("false".equals(s)) { result.add(new DecimalType(0).noExtensions()); + } return result; } @@ -3289,12 +3472,13 @@ public class FHIRPathEngine { List n1 = execute(context, focus, exp.getParameters().get(0), true); Equality v = asBool(n1); - if (v == Equality.True) + if (v == Equality.True) { return execute(context, focus, exp.getParameters().get(1), true); - else if (exp.getParameters().size() < 3) + } else if (exp.getParameters().size() < 3) { return new ArrayList(); - else + } else { return execute(context, focus, exp.getParameters().get(2), true); + } } @@ -3303,8 +3487,9 @@ public class FHIRPathEngine { int i1 = Integer.parseInt(n1.get(0).primitiveValue()); List result = new ArrayList(); - for (int i = 0; i < Math.min(focus.size(), i1); i++) + for (int i = 0; i < Math.min(focus.size(), i1); i++) { result.add(focus.get(i)); + } return result; } @@ -3312,12 +3497,14 @@ public class FHIRPathEngine { private List funcUnion(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List result = new ArrayList(); for (Base item : focus) { - if (!doContains(result, item)) + if (!doContains(result, item)) { result.add(item); + } } for (Base item : execute(context, focus, exp.getParameters().get(0), true)) { - if (!doContains(result, item)) + if (!doContains(result, item)) { result.add(item); + } } return result; } @@ -3338,8 +3525,9 @@ public class FHIRPathEngine { List other = execute(context, focus, exp.getParameters().get(0), true); for (Base item : focus) { - if (!doContains(result, item) && doContains(other, item)) + if (!doContains(result, item) && doContains(other, item)) { result.add(item); + } } return result; } @@ -3349,32 +3537,37 @@ public class FHIRPathEngine { List other = execute(context, focus, exp.getParameters().get(0), true); for (Base item : focus) { - if (!doContains(other, item)) + if (!doContains(other, item)) { result.add(item); + } } return result; } private List funcSingle(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { - if (focus.size() == 1) + if (focus.size() == 1) { return focus; - throw new PathEngineException(String.format("Single() : checking for 1 item but found %d items", focus.size())); + } + throw makeException(I18nConstants.FHIRPATH_NO_COLLECTION, "single", focus.size()); } private List funcIs(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { - if (focus.size() == 0 || focus.size() > 1) + if (focus.size() == 0 || focus.size() > 1) { return makeBoolean(false); + } String ns = null; String n = null; ExpressionNode texp = exp.getParameters().get(0); - if (texp.getKind() != Kind.Name) - throw new PathEngineException("Unsupported Expression type for Parameter on Is"); + if (texp.getKind() != Kind.Name) { + throw makeException(I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "0", "is"); + } if (texp.getInner() != null) { - if (texp.getInner().getKind() != Kind.Name) - throw new PathEngineException("Unsupported Expression type for Parameter on Is"); + if (texp.getInner().getKind() != Kind.Name) { + throw makeException(I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "1", "is"); + } ns = texp.getName(); n = texp.getInner().getName(); } else if (Utilities.existsInList(texp.getName(), "Boolean", "Integer", "Decimal", "String", "DateTime", "Time", "SimpleTypeInfo", "ClassInfo")) { @@ -3385,12 +3578,14 @@ public class FHIRPathEngine { n = texp.getName(); } if (ns.equals("System")) { - if (focus.get(0) instanceof Resource) + if (focus.get(0) instanceof Resource) { return makeBoolean(false); - if (!(focus.get(0) instanceof Element) || ((Element) focus.get(0)).isDisallowExtensions()) + } + if (!(focus.get(0) instanceof Element) || ((Element) focus.get(0)).isDisallowExtensions()) { return makeBoolean(n.equals(Utilities.capitalize(focus.get(0).fhirType()))); - else + } else { return makeBoolean(false); + } } else if (ns.equals("FHIR")) { return makeBoolean(n.equals(focus.get(0).fhirType())); } else { @@ -3402,18 +3597,23 @@ public class FHIRPathEngine { private List funcAs(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); String tn; - if (exp.getParameters().get(0).getInner() != null) + if (exp.getParameters().get(0).getInner() != null) { tn = exp.getParameters().get(0).getName()+"."+exp.getParameters().get(0).getInner().getName(); - else + } else { tn = "FHIR."+exp.getParameters().get(0).getName(); + } for (Base b : focus) { if (tn.startsWith("System.")) { - if (b instanceof Element &&((Element) b).isDisallowExtensions()) - if (b.hasType(tn.substring(7))) - result.add(b); - } else if (tn.startsWith("FHIR.")) { - if (b.hasType(tn.substring(5))) + if (b instanceof Element &&((Element) b).isDisallowExtensions()) { + if (b.hasType(tn.substring(7))) { result.add(b); + } + } + + } else if (tn.startsWith("FHIR.")) { + if (b.hasType(tn.substring(5))) { + result.add(b); + } } } return result; @@ -3421,8 +3621,9 @@ public class FHIRPathEngine { private List funcType(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - for (Base item : focus) + for (Base item : focus) { result.add(new ClassTypeInfo(item)); + } return result; } @@ -3452,8 +3653,9 @@ public class FHIRPathEngine { private List funcAggregate(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List total = new ArrayList(); - if (exp.parameterCount() > 1) + if (exp.parameterCount() > 1) { total = execute(context, focus, exp.getParameters().get(1), false); + } List pc = new ArrayList(); for (Base item : focus) { @@ -3467,10 +3669,12 @@ public class FHIRPathEngine { private List funcIsDistinct(ExecutionContext context, List focus, ExpressionNode exp) { - if (focus.size() < 1) + if (focus.size() < 1) { return makeBoolean(true); - if (focus.size() == 1) + } + if (focus.size() == 1) { return makeBoolean(true); + } boolean distinct = true; for (int i = 0; i < focus.size(); i++) { @@ -3563,10 +3767,11 @@ public class FHIRPathEngine { if (item.fhirType().equals("Reference")) { refContext = item; Property p = item.getChildByName("reference"); - if (p != null && p.hasValues()) + if (p != null && p.hasValues()) { s = convertToString(p.getValues().get(0)); - else + } else { s = null; // a reference without any valid actual reference (just identifier or display, but we can't resolve it) + } } if (item.fhirType().equals("canonical")) { s = item.primitiveValue(); @@ -3587,8 +3792,9 @@ public class FHIRPathEngine { } else if (hostServices != null) { res = hostServices.resolveReference(context.appInfo, s, refContext); } - if (res != null) + if (res != null) { result.add(res); + } } } @@ -3618,8 +3824,9 @@ public class FHIRPathEngine { for (Base ex : ext) { List vl = new ArrayList(); getChildrenByName(ex, "url", vl); - if (convertToString(vl).equals(url)) + if (convertToString(vl).equals(url)) { result.add(ex); + } } } return result; @@ -3751,8 +3958,9 @@ public class FHIRPathEngine { if (exp.getParameters().size() == 2) { List n2 = execute(context, focus, exp.getParameters().get(1), true); log(name, n2); - } else + } else { log(name, focus); + } return focus; } @@ -3761,14 +3969,15 @@ public class FHIRPathEngine { if (!convertToBoolean(n1)) { List n2 = execute(context, focus, exp.getParameters().get(1), true); String name = n2.get(0).primitiveValue(); - throw new FHIRException("check failed: "+name); + throw makeException(I18nConstants.FHIRPATH_CHECK_FAILED, name); } return focus; } private List funcDistinct(ExecutionContext context, List focus, ExpressionNode exp) { - if (focus.size() <= 1) + if (focus.size() <= 1) { return focus; + } List result = new ArrayList(); for (int i = 0; i < focus.size(); i++) { @@ -3782,8 +3991,9 @@ public class FHIRPathEngine { break; } } - if (!found) + if (!found) { result.add(focus.get(i)); + } } return result; } @@ -3794,14 +4004,15 @@ public class FHIRPathEngine { if (focus.size() == 1 && !Utilities.noString(sw)) { String st = convertToString(focus.get(0)); - if (Utilities.noString(st)) + if (Utilities.noString(st)) { result.add(new BooleanType(false).noExtensions()); - else { + } else { boolean ok = st.matches(sw); result.add(new BooleanType(ok).noExtensions()); } - } else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } @@ -3815,10 +4026,11 @@ public class FHIRPathEngine { result.add(new BooleanType(true).noExtensions()); } else { String st = convertToString(focus.get(0)); - if (Utilities.noString(st)) + if (Utilities.noString(st)) { result.add(new BooleanType(false).noExtensions()); - else + } else { result.add(new BooleanType(st.contains(sw)).noExtensions()); + } } return result; } @@ -3837,8 +4049,9 @@ public class FHIRPathEngine { if (focus.size() == 1) { String s = convertToString(focus.get(0)); result.add(new BooleanType(!Utilities.noString(s)).noExtensions()); - } else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } @@ -3852,10 +4065,11 @@ public class FHIRPathEngine { result.add(new BooleanType(true).noExtensions()); } else { String s = convertToString(focus.get(0)); - if (s == null) + if (s == null) { result.add(new BooleanType(false).noExtensions()); - else + } else { result.add(new BooleanType(s.startsWith(sw)).noExtensions()); + } } return result; } @@ -3864,8 +4078,9 @@ public class FHIRPathEngine { List result = new ArrayList(); if (focus.size() == 1) { String s = convertToString(focus.get(0)); - if (!Utilities.noString(s)) + if (!Utilities.noString(s)) { result.add(new StringType(s.toLowerCase()).noExtensions()); + } } return result; } @@ -3874,8 +4089,9 @@ public class FHIRPathEngine { List result = new ArrayList(); if (focus.size() == 1) { String s = convertToString(focus.get(0)); - if (!Utilities.noString(s)) + if (!Utilities.noString(s)) { result.add(new StringType(s.toUpperCase()).noExtensions()); + } } return result; } @@ -3884,8 +4100,9 @@ public class FHIRPathEngine { List result = new ArrayList(); if (focus.size() == 1) { String s = convertToString(focus.get(0)); - for (char c : s.toCharArray()) + for (char c : s.toCharArray()) { result.add(new StringType(String.valueOf(c)).noExtensions()); + } } return result; } @@ -3900,10 +4117,11 @@ public class FHIRPathEngine { result.add(new IntegerType(0).noExtensions()); } else { String s = convertToString(focus.get(0)); - if (s == null) + if (s == null) { result.add(new IntegerType(0).noExtensions()); - else + } else { result.add(new IntegerType(s.indexOf(sw)).noExtensions()); + } } return result; } @@ -3921,14 +4139,17 @@ public class FHIRPathEngine { if (focus.size() == 1) { String sw = convertToString(focus.get(0)); String s; - if (i1 < 0 || i1 >= sw.length()) + if (i1 < 0 || i1 >= sw.length()) { return new ArrayList(); - if (exp.parameterCount() == 2) + } + if (exp.parameterCount() == 2) { s = sw.substring(i1, Math.min(sw.length(), i1+i2)); - else + } else { s = sw.substring(i1); - if (!Utilities.noString(s)) + } + if (!Utilities.noString(s)) { result.add(new StringType(s).noExtensions()); + } } return result; } @@ -3936,68 +4157,73 @@ public class FHIRPathEngine { private List funcToInteger(ExecutionContext context, List focus, ExpressionNode exp) { String s = convertToString(focus); List result = new ArrayList(); - if (Utilities.isInteger(s)) + if (Utilities.isInteger(s)) { result.add(new IntegerType(s).noExtensions()); - else if ("true".equals(s)) + } else if ("true".equals(s)) { result.add(new IntegerType(1).noExtensions()); - else if ("false".equals(s)) + } else if ("false".equals(s)) { result.add(new IntegerType(0).noExtensions()); + } return result; } private List funcIsInteger(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else if (focus.get(0) instanceof IntegerType) + } else if (focus.get(0) instanceof IntegerType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof BooleanType) + } else if (focus.get(0) instanceof BooleanType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof StringType) + } else if (focus.get(0) instanceof StringType) { result.add(new BooleanType(Utilities.isInteger(convertToString(focus.get(0)))).noExtensions()); - else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } private List funcIsBoolean(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else if (focus.get(0) instanceof IntegerType) + } else if (focus.get(0) instanceof IntegerType) { result.add(new BooleanType(((IntegerType) focus.get(0)).getValue() >= 0 && ((IntegerType) focus.get(0)).getValue() <= 1).noExtensions()); - else if (focus.get(0) instanceof DecimalType) + } else if (focus.get(0) instanceof DecimalType) { result.add(new BooleanType(((DecimalType) focus.get(0)).getValue().compareTo(BigDecimal.ZERO) == 0 || ((DecimalType) focus.get(0)).getValue().compareTo(BigDecimal.ONE) == 0).noExtensions()); - else if (focus.get(0) instanceof BooleanType) + } else if (focus.get(0) instanceof BooleanType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof StringType) + } else if (focus.get(0) instanceof StringType) { result.add(new BooleanType(Utilities.existsInList(convertToString(focus.get(0)).toLowerCase(), "true", "false")).noExtensions()); - else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } private List funcIsDateTime(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else if (focus.get(0) instanceof DateTimeType || focus.get(0) instanceof DateType) + } else if (focus.get(0) instanceof DateTimeType || focus.get(0) instanceof DateType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof StringType) + } else if (focus.get(0) instanceof StringType) { result.add(new BooleanType((convertToString(focus.get(0)).matches ("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"))).noExtensions()); - else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } private List funcConformsTo(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { - if (hostServices == null) - throw new FHIRException("Unable to check conformsTo - no hostservices provided"); + if (hostServices == null) { + throw makeException(I18nConstants.FHIRPATH_HO_HOST_SERVICES, "conformsTo"); + } List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else { + } else { String url = convertToString(execute(context, focus, exp.getParameters().get(0), true)); result.add(new BooleanType(hostServices.conformsToProfile(context.appInfo, focus.get(0), url)).noExtensions()); } @@ -4006,101 +4232,110 @@ public class FHIRPathEngine { private List funcIsTime(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else if (focus.get(0) instanceof TimeType) + } else if (focus.get(0) instanceof TimeType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof StringType) + } else if (focus.get(0) instanceof StringType) { result.add(new BooleanType((convertToString(focus.get(0)).matches ("T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"))).noExtensions()); - else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } private List funcIsString(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else if (!(focus.get(0) instanceof DateTimeType) && !(focus.get(0) instanceof TimeType)) + } else if (!(focus.get(0) instanceof DateTimeType) && !(focus.get(0) instanceof TimeType)) { result.add(new BooleanType(true).noExtensions()); - else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } private List funcIsQuantity(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else if (focus.get(0) instanceof IntegerType) + } else if (focus.get(0) instanceof IntegerType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof DecimalType) + } else if (focus.get(0) instanceof DecimalType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof Quantity) + } else if (focus.get(0) instanceof Quantity) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof BooleanType) + } else if (focus.get(0) instanceof BooleanType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof StringType) { + } else if (focus.get(0) instanceof StringType) { Quantity q = parseQuantityString(focus.get(0).primitiveValue()); result.add(new BooleanType(q != null).noExtensions()); - } else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } public Quantity parseQuantityString(String s) { - if (s == null) + if (s == null) { return null; + } s = s.trim(); if (s.contains(" ")) { String v = s.substring(0, s.indexOf(" ")).trim(); s = s.substring(s.indexOf(" ")).trim(); - if (!Utilities.isDecimal(v, false)) + if (!Utilities.isDecimal(v, false)) { return null; - if (s.startsWith("'") && s.endsWith("'")) + } + if (s.startsWith("'") && s.endsWith("'")) { return Quantity.fromUcum(v, s.substring(1, s.length()-1)); - if (s.equals("year") || s.equals("years")) + } + if (s.equals("year") || s.equals("years")) { return Quantity.fromUcum(v, "a"); - else if (s.equals("month") || s.equals("months")) + } else if (s.equals("month") || s.equals("months")) { return Quantity.fromUcum(v, "mo"); - else if (s.equals("week") || s.equals("weeks")) + } else if (s.equals("week") || s.equals("weeks")) { return Quantity.fromUcum(v, "wk"); - else if (s.equals("day") || s.equals("days")) + } else if (s.equals("day") || s.equals("days")) { return Quantity.fromUcum(v, "d"); - else if (s.equals("hour") || s.equals("hours")) + } else if (s.equals("hour") || s.equals("hours")) { return Quantity.fromUcum(v, "h"); - else if (s.equals("minute") || s.equals("minutes")) + } else if (s.equals("minute") || s.equals("minutes")) { return Quantity.fromUcum(v, "min"); - else if (s.equals("second") || s.equals("seconds")) + } else if (s.equals("second") || s.equals("seconds")) { return Quantity.fromUcum(v, "s"); - else if (s.equals("millisecond") || s.equals("milliseconds")) + } else if (s.equals("millisecond") || s.equals("milliseconds")) { return Quantity.fromUcum(v, "ms"); - else - return null; - } else { - if (Utilities.isDecimal(s, true)) - return new Quantity().setValue(new BigDecimal(s)).setSystem("http://unitsofmeasure.org").setCode("1"); - else + } else { return null; + } + } else { + if (Utilities.isDecimal(s, true)) { + return new Quantity().setValue(new BigDecimal(s)).setSystem("http://unitsofmeasure.org").setCode("1"); + } else { + return null; + } } } private List funcIsDecimal(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() != 1) + if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); - else if (focus.get(0) instanceof IntegerType) + } else if (focus.get(0) instanceof IntegerType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof BooleanType) + } else if (focus.get(0) instanceof BooleanType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof DecimalType) + } else if (focus.get(0) instanceof DecimalType) { result.add(new BooleanType(true).noExtensions()); - else if (focus.get(0) instanceof StringType) + } else if (focus.get(0) instanceof StringType) { result.add(new BooleanType(Utilities.isDecimal(convertToString(focus.get(0)), true)).noExtensions()); - else + } else { result.add(new BooleanType(false).noExtensions()); + } return result; } @@ -4115,29 +4350,33 @@ public class FHIRPathEngine { int i1 = Integer.parseInt(n1.get(0).primitiveValue()); List result = new ArrayList(); - for (int i = i1; i < focus.size(); i++) + for (int i = i1; i < focus.size(); i++) { result.add(focus.get(i)); + } return result; } private List funcTail(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - for (int i = 1; i < focus.size(); i++) + for (int i = 1; i < focus.size(); i++) { result.add(focus.get(i)); + } return result; } private List funcLast(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() > 0) + if (focus.size() > 0) { result.add(focus.get(focus.size()-1)); + } return result; } private List funcFirst(ExecutionContext context, List focus, ExpressionNode exp) { List result = new ArrayList(); - if (focus.size() > 0) + if (focus.size() > 0) { result.add(focus.get(0)); + } return result; } @@ -4149,8 +4388,9 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); - if (v == Equality.True) + if (v == Equality.True) { result.add(item); + } } return result; } @@ -4170,8 +4410,9 @@ public class FHIRPathEngine { private List funcItem(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List result = new ArrayList(); String s = convertToString(execute(context, focus, exp.getParameters().get(0), true)); - if (Utilities.isInteger(s) && Integer.parseInt(s) < focus.size()) + if (Utilities.isInteger(s) && Integer.parseInt(s) < focus.size()) { result.add(focus.get(Integer.parseInt(s))); + } return result; } @@ -4184,8 +4425,9 @@ public class FHIRPathEngine { private List funcNot(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { List result = new ArrayList(); Equality v = asBool(focus); - if (v != Equality.Null) + if (v != Equality.Null) { result.add(new BooleanType(v != Equality.True)); + } return result; } @@ -4207,143 +4449,159 @@ public class FHIRPathEngine { } private void getChildTypesByName(String type, String name, TypeDetails result) throws PathEngineException, DefinitionException { - if (Utilities.noString(type)) - throw new PathEngineException("No type provided in BuildToolPathEvaluator.getChildTypesByName"); - if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml")) + if (Utilities.noString(type)) { + throw makeException(I18nConstants.FHIRPATH_NO_TYPE, "", "getChildTypesByName"); + } + if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml")) { return; - if (type.startsWith(Constants.NS_SYSTEM_TYPE)) + } + if (type.startsWith(Constants.NS_SYSTEM_TYPE)) { return; - + } + if (type.equals(TypeDetails.FP_SimpleTypeInfo)) { getSimpleTypeChildTypesByName(name, result); } else if (type.equals(TypeDetails.FP_ClassInfo)) { getClassInfoChildTypesByName(name, result); } else { - String url = null; - if (type.contains("#")) { - url = type.substring(0, type.indexOf("#")); - } else { - url = type; - } - String tail = ""; - StructureDefinition sd = worker.fetchResource(StructureDefinition.class, url); - if (sd == null) - throw new DefinitionException("Unknown type "+type); // this really is an error, because we can only get to here if the internal infrastrucgture is wrong - List sdl = new ArrayList(); - ElementDefinitionMatch m = null; - if (type.contains("#")) - m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false); - if (m != null && hasDataType(m.definition)) { - if (m.fixedType != null) - { - StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs())); - if (dt == null) - throw new DefinitionException("unknown data type "+m.fixedType); - sdl.add(dt); - } else - for (TypeRefComponent t : m.definition.getType()) { - StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs())); - if (dt == null) - throw new DefinitionException("unknown data type "+t.getCode()); - sdl.add(dt); - } - } else { - sdl.add(sd); + String url = null; if (type.contains("#")) { - tail = type.substring(type.indexOf("#")+1); - tail = tail.substring(tail.indexOf(".")); + url = type.substring(0, type.indexOf("#")); + } else { + url = type; + } + String tail = ""; + StructureDefinition sd = worker.fetchResource(StructureDefinition.class, url); + if (sd == null) { + throw makeException(I18nConstants.FHIRPATH_NO_TYPE, url, "getChildTypesByName"); + } + List sdl = new ArrayList(); + ElementDefinitionMatch m = null; + if (type.contains("#")) + m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false); + if (m != null && hasDataType(m.definition)) { + if (m.fixedType != null) { + StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs())); + if (dt == null) { + throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs()), "getChildTypesByName"); + } + sdl.add(dt); + } else + for (TypeRefComponent t : m.definition.getType()) { + StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs())); + if (dt == null) { + throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs()), "getChildTypesByName"); + } + sdl.add(dt); + } + } else { + sdl.add(sd); + if (type.contains("#")) { + tail = type.substring(type.indexOf("#")+1); + tail = tail.substring(tail.indexOf(".")); + } } - } - for (StructureDefinition sdi : sdl) { - String path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."; - if (name.equals("**")) { - assert(result.getCollectionStatus() == CollectionStatus.UNORDERED); - for (ElementDefinition ed : sdi.getSnapshot().getElement()) { - if (ed.getPath().startsWith(path)) - for (TypeRefComponent t : ed.getType()) { - if (t.hasCode() && t.getCodeElement().hasValue()) { - String tn = null; - if (t.getCode().equals("Element") || t.getCode().equals("BackboneElement")) - tn = sdi.getType()+"#"+ed.getPath(); - else - tn = t.getCode(); - if (t.getCode().equals("Resource")) { - for (String rn : worker.getResourceNames()) { - if (!result.hasType(worker, rn)) { - getChildTypesByName(result.addType(rn), "**", result); - } + for (StructureDefinition sdi : sdl) { + String path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."; + if (name.equals("**")) { + assert(result.getCollectionStatus() == CollectionStatus.UNORDERED); + for (ElementDefinition ed : sdi.getSnapshot().getElement()) { + if (ed.getPath().startsWith(path)) + for (TypeRefComponent t : ed.getType()) { + if (t.hasCode() && t.getCodeElement().hasValue()) { + String tn = null; + if (t.getCode().equals("Element") || t.getCode().equals("BackboneElement")) { + tn = sdi.getType()+"#"+ed.getPath(); + } else { + tn = t.getCode(); } - } else if (!result.hasType(worker, tn)) { - getChildTypesByName(result.addType(tn), "**", result); + if (t.getCode().equals("Resource")) { + for (String rn : worker.getResourceNames()) { + if (!result.hasType(worker, rn)) { + getChildTypesByName(result.addType(rn), "**", result); + } + } + } else if (!result.hasType(worker, tn)) { + getChildTypesByName(result.addType(tn), "**", result); + } + } + } + } + } else if (name.equals("*")) { + assert(result.getCollectionStatus() == CollectionStatus.UNORDERED); + for (ElementDefinition ed : sdi.getSnapshot().getElement()) { + if (ed.getPath().startsWith(path) && !ed.getPath().substring(path.length()).contains(".")) + for (TypeRefComponent t : ed.getType()) { + if (Utilities.noString(t.getCode())) { // Element.id or Extension.url + result.addType("System.string"); + } else if (t.getCode().equals("Element") || t.getCode().equals("BackboneElement")) { + result.addType(sdi.getType()+"#"+ed.getPath()); + } else if (t.getCode().equals("Resource")) { + result.addTypes(worker.getResourceNames()); + } else { + result.addType(t.getCode()); + } + } + } + } else { + path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."+name; + + ElementDefinitionMatch ed = getElementDefinition(sdi, path, false); + if (ed != null) { + if (!Utilities.noString(ed.getFixedType())) + result.addType(ed.getFixedType()); + else { + for (TypeRefComponent t : ed.getDefinition().getType()) { + if (Utilities.noString(t.getCode())) { + if (Utilities.existsInList(ed.getDefinition().getId(), "Element.id", "Extension.url") || Utilities.existsInList(ed.getDefinition().getBase().getPath(), "Resource.id", "Element.id", "Extension.url")) { + result.addType(TypeDetails.FP_NS, "string"); + } + break; // throw new PathEngineException("Illegal reference to primitive value attribute @ "+path); + } + + ProfiledType pt = null; + if (t.getCode().equals("Element") || t.getCode().equals("BackboneElement")) { + pt = new ProfiledType(sdi.getUrl()+"#"+path); + } else if (t.getCode().equals("Resource")) { + result.addTypes(worker.getResourceNames()); + } else { + pt = new ProfiledType(t.getCode()); + } + if (pt != null) { + if (t.hasProfile()) { + pt.addProfiles(t.getProfile()); + } + if (ed.getDefinition().hasBinding()) { + pt.addBinding(ed.getDefinition().getBinding()); + } + result.addType(pt); } } } - } - } else if (name.equals("*")) { - assert(result.getCollectionStatus() == CollectionStatus.UNORDERED); - for (ElementDefinition ed : sdi.getSnapshot().getElement()) { - if (ed.getPath().startsWith(path) && !ed.getPath().substring(path.length()).contains(".")) - for (TypeRefComponent t : ed.getType()) { - if (Utilities.noString(t.getCode())) // Element.id or Extension.url - result.addType("System.string"); - else if (t.getCode().equals("Element") || t.getCode().equals("BackboneElement")) - result.addType(sdi.getType()+"#"+ed.getPath()); - else if (t.getCode().equals("Resource")) - result.addTypes(worker.getResourceNames()); - else - result.addType(t.getCode()); - } - } - } else { - path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."+name; - - ElementDefinitionMatch ed = getElementDefinition(sdi, path, false); - if (ed != null) { - if (!Utilities.noString(ed.getFixedType())) - result.addType(ed.getFixedType()); - else - for (TypeRefComponent t : ed.getDefinition().getType()) { - if (Utilities.noString(t.getCode())) { - if (Utilities.existsInList(ed.getDefinition().getId(), "Element.id", "Extension.url") || Utilities.existsInList(ed.getDefinition().getBase().getPath(), "Resource.id", "Element.id", "Extension.url")) - result.addType(TypeDetails.FP_NS, "string"); - break; // throw new PathEngineException("Illegal reference to primitive value attribute @ "+path); - } - - ProfiledType pt = null; - if (t.getCode().equals("Element") || t.getCode().equals("BackboneElement")) - pt = new ProfiledType(sdi.getUrl()+"#"+path); - else if (t.getCode().equals("Resource")) - result.addTypes(worker.getResourceNames()); - else - pt = new ProfiledType(t.getCode()); - if (pt != null) { - if (t.hasProfile()) - pt.addProfiles(t.getProfile()); - if (ed.getDefinition().hasBinding()) - pt.addBinding(ed.getDefinition().getBinding()); - result.addType(pt); - } - } + } } } } - } } private void getClassInfoChildTypesByName(String name, TypeDetails result) { - if (name.equals("namespace")) + if (name.equals("namespace")) { result.addType(TypeDetails.FP_String); - if (name.equals("name")) + } + if (name.equals("name")) { result.addType(TypeDetails.FP_String); + } } private void getSimpleTypeChildTypesByName(String name, TypeDetails result) { - if (name.equals("namespace")) + if (name.equals("namespace")) { result.addType(TypeDetails.FP_String); - if (name.equals("name")) + } + if (name.equals("name")) { result.addType(TypeDetails.FP_String); + } } @@ -4352,25 +4610,30 @@ public class FHIRPathEngine { if (ed.getPath().equals(path)) { if (ed.hasContentReference()) { return getElementDefinitionById(sd, ed.getContentReference()); - } else + } else { return new ElementDefinitionMatch(ed, null); + } } - if (ed.getPath().endsWith("[x]") && path.startsWith(ed.getPath().substring(0, ed.getPath().length()-3)) && path.length() == ed.getPath().length()-3) + if (ed.getPath().endsWith("[x]") && path.startsWith(ed.getPath().substring(0, ed.getPath().length()-3)) && path.length() == ed.getPath().length()-3) { return new ElementDefinitionMatch(ed, null); + } if (allowTypedName && ed.getPath().endsWith("[x]") && path.startsWith(ed.getPath().substring(0, ed.getPath().length()-3)) && path.length() > ed.getPath().length()-3) { - String s = Utilities.uncapitalize(path.substring(ed.getPath().length()-3)); - if (primitiveTypes.contains(s)) + String s = Utilities.uncapitalize(path.substring(ed.getPath().length()-3)); + if (primitiveTypes.contains(s)) { return new ElementDefinitionMatch(ed, s); - else - return new ElementDefinitionMatch(ed, path.substring(ed.getPath().length()-3)); + } else { + return new ElementDefinitionMatch(ed, path.substring(ed.getPath().length()-3)); + } } if (ed.getPath().contains(".") && path.startsWith(ed.getPath()+".") && (ed.getType().size() > 0) && !isAbstractType(ed.getType())) { // now we walk into the type. - if (ed.getType().size() > 1) // if there's more than one type, the test above would fail this - throw new PathEngineException("Internal typing issue...."); + if (ed.getType().size() > 1) { // if there's more than one type, the test above would fail this + throw new Error("Internal typing issue...."); + } StructureDefinition nsd = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs())); - if (nsd == null) - throw new PathEngineException("Unknown type "+ed.getType().get(0).getCode()); + if (nsd == null) { + throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ed.getType().get(0).getCode(), "getElementDefinition"); + } return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName); } if (ed.hasContentReference() && path.startsWith(ed.getPath()+".")) { @@ -4382,14 +4645,16 @@ public class FHIRPathEngine { } private boolean isAbstractType(List list) { - return list.size() != 1 ? true : Utilities.existsInList(list.get(0).getCode(), "Element", "BackboneElement", "Resource", "DomainResource"); -} + return list.size() != 1 ? true : Utilities.existsInList(list.get(0).getCode(), "Element", "BackboneElement", "Resource", "DomainResource"); + } private boolean hasType(ElementDefinition ed, String s) { - for (TypeRefComponent t : ed.getType()) - if (s.equalsIgnoreCase(t.getCode())) + for (TypeRefComponent t : ed.getType()) { + if (s.equalsIgnoreCase(t.getCode())) { return true; + } + } return false; } @@ -4399,8 +4664,9 @@ public class FHIRPathEngine { private ElementDefinitionMatch getElementDefinitionById(StructureDefinition sd, String ref) { for (ElementDefinition ed : sd.getSnapshot().getElement()) { - if (ref.equals("#"+ed.getId())) + if (ref.equals("#"+ed.getId())) { return new ElementDefinitionMatch(ed, null); + } } return null; } @@ -4412,8 +4678,9 @@ public class FHIRPathEngine { public String takeLog() { - if (!hasLog()) + if (!hasLog()) { return ""; + } String s = log.toString(); log = new StringBuilder(); return s; @@ -4434,15 +4701,16 @@ public class FHIRPathEngine { StructureDefinition sd = profile; ElementDefinition focus = null; boolean okToNotResolve = false; - + if (expr.getKind() == Kind.Name) { if (element.hasSlicing()) { ElementDefinition slice = pickMandatorySlice(sd, element); - if (slice == null) - throw new DefinitionException("Error in discriminator at "+element.getId()+": found a sliced element while resolving the fixed value for one of the slices"); + if (slice == null) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getId()); + } element = slice; } - + if (expr.getName().equals("$this")) { focus = element; } else { @@ -4452,8 +4720,9 @@ public class FHIRPathEngine { if (childDefinitions.isEmpty()) { sd = fetchStructureByType(element); - if (sd == null) - throw new DefinitionException("Problem with use of resolve() - profile '"+element.getType().get(0).getProfile()+"' on "+element.getId()+" could not be resolved"); + if (sd == null) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getType().get(0).getProfile(), element.getId()); + } childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep()); } for (ElementDefinition t : childDefinitions) { @@ -4465,65 +4734,76 @@ public class FHIRPathEngine { } } else if (expr.getKind() == Kind.Function) { if ("resolve".equals(expr.getName())) { - if (!element.hasType()) - throw new DefinitionException("illegal use of resolve() in discriminator - no type on element "+element.getId()); - if (element.getType().size() > 1) - throw new DefinitionException("illegal use of resolve() in discriminator - Multiple possible types on "+element.getId()); - if (!element.getType().get(0).hasTarget()) - throw new DefinitionException("illegal use of resolve() in discriminator - type on "+element.getId()+" is not Reference ("+element.getType().get(0).getCode()+")"); - if (element.getType().get(0).getTargetProfile().size() > 1) - throw new DefinitionException("illegal use of resolve() in discriminator - Multiple possible target type profiles on "+element.getId()); + if (!element.hasType()) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getId()); + } + if (element.getType().size() > 1) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getId()); + } + if (!element.getType().get(0).hasTarget()) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getId(), element.getType().get(0).getCode()+")"); + } + if (element.getType().get(0).getTargetProfile().size() > 1) { + throw makeException(I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getId()); + } sd = worker.fetchResource(StructureDefinition.class, element.getType().get(0).getTargetProfile().get(0).getValue()); - if (sd == null) - throw new DefinitionException("Problem with use of resolve() - profile '"+element.getType().get(0).getTargetProfile()+"' on "+element.getId()+" could not be resolved"); + if (sd == null) { + throw makeException(I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getType().get(0).getTargetProfile(), element.getId()); + } focus = sd.getSnapshot().getElementFirstRep(); } else if ("extension".equals(expr.getName())) { String targetUrl = expr.getParameters().get(0).getConstant().primitiveValue(); -// targetUrl = targetUrl.substring(1,targetUrl.length()-1); + // targetUrl = targetUrl.substring(1,targetUrl.length()-1); List childDefinitions = profileUtilities.getChildMap(sd, element); for (ElementDefinition t : childDefinitions) { if (t.getPath().endsWith(".extension") && t.hasSliceName()) { - StructureDefinition exsd = worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue()); - while (exsd!=null && !exsd.getBaseDefinition().equals("http://hl7.org/fhir/StructureDefinition/Extension")) - exsd = worker.fetchResource(StructureDefinition.class, exsd.getBaseDefinition()); - if (exsd.getUrl().equals(targetUrl)) { - if (profileUtilities.getChildMap(sd, t).isEmpty()) - sd = exsd; - focus = t; - break; - } + StructureDefinition exsd = worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue()); + while (exsd!=null && !exsd.getBaseDefinition().equals("http://hl7.org/fhir/StructureDefinition/Extension")) { + exsd = worker.fetchResource(StructureDefinition.class, exsd.getBaseDefinition()); + } + if (exsd.getUrl().equals(targetUrl)) { + if (profileUtilities.getChildMap(sd, t).isEmpty()) { + sd = exsd; + } + focus = t; + break; + } } } } else if ("ofType".equals(expr.getName())) { - if (!element.hasType()) - throw new DefinitionException("illegal use of ofType() in discriminator - no type on element "+element.getId()); - if (element.getType().size() > 1) - throw new DefinitionException("illegal use of ofType() in discriminator - Multiple possible types on "+element.getId()); - if (!element.getType().get(0).hasCode()) - throw new DefinitionException("illegal use of ofType() in discriminator - Type has no code on "+element.getId()); + if (!element.hasType()) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getId()); + } + if (element.getType().size() > 1) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE, element.getId()); + } + if (!element.getType().get(0).hasCode()) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getId()); + } String atn = element.getType().get(0).getCode(); String stn = expr.getParameters().get(0).getName(); okToNotResolve = true; if ((atn.equals(stn))) { focus = element; } - } else - throw new DefinitionException("illegal function name "+expr.getName()+"() in discriminator"); + } else { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName()); + } } else if (expr.getKind() == Kind.Group) { - throw new DefinitionException("illegal expression syntax in discriminator (group)"); + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP); } else if (expr.getKind() == Kind.Constant) { - throw new DefinitionException("illegal expression syntax in discriminator (const)"); + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST); } if (focus == null) { if (okToNotResolve) { return null; } else { - throw new DefinitionException("Unable to resolve discriminator in definitions: "+expr.toString()); + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString()); } - } else if (expr.getInner() == null) + } else if (expr.getInner() == null) { return focus; - else { + } else { return evaluateDefinition(expr.getInner(), sd, focus); } } @@ -4531,37 +4811,43 @@ public class FHIRPathEngine { private ElementDefinition pickMandatorySlice(StructureDefinition sd, ElementDefinition element) throws DefinitionException { List list = profileUtilities.getSliceList(sd, element); for (ElementDefinition ed : list) { - if (ed.getMin() > 0) + if (ed.getMin() > 0) { return ed; + } } return null; } private StructureDefinition fetchStructureByType(ElementDefinition ed) throws DefinitionException { - if (ed.getType().size() == 0) - throw new DefinitionException("Error in discriminator at "+ed.getId()+": no children, no type"); - if (ed.getType().size() > 1) - throw new DefinitionException("Error in discriminator at "+ed.getId()+": no children, multiple types"); - if (ed.getType().get(0).getProfile().size() > 1) - throw new DefinitionException("Error in discriminator at "+ed.getId()+": no children, multiple type profiles"); - if (ed.getType().get(0).hasProfile()) + if (ed.getType().size() == 0) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getId()); + } + if (ed.getType().size() > 1) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getId()); + } + if (ed.getType().get(0).getProfile().size() > 1) { + throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getId()); + } + if (ed.getType().get(0).hasProfile()) { return worker.fetchResource(StructureDefinition.class, ed.getType().get(0).getProfile().get(0).getValue()); - else + } else { return worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs())); + } } private boolean tailMatches(ElementDefinition t, String d) { String tail = tailDot(t.getPath()); - if (d.contains("[")) + if (d.contains("[")) { return tail.startsWith(d.substring(0, d.indexOf('['))); - else if (tail.equals(d)) + } else if (tail.equals(d)) { return true; - else if (t.getType().size() == 1 && t.getType().get(0).getCode() != null && t.getPath() != null && t.getPath().toUpperCase().endsWith(t.getType().get(0).getCode().toUpperCase())) + } else if (t.getType().size() == 1 && t.getType().get(0).getCode() != null && t.getPath() != null && t.getPath().toUpperCase().endsWith(t.getType().get(0).getCode().toUpperCase())) { return tail.startsWith(d); - else if (t.getPath().endsWith("[x]") && tail.startsWith(d)) + } else if (t.getPath().endsWith("[x]") && tail.startsWith(d)) { return true; + } return false; } @@ -4570,12 +4856,13 @@ public class FHIRPathEngine { } private Equality asBool(List items) throws PathEngineException { - if (items.size() == 0) + if (items.size() == 0) { return Equality.Null; - else if (items.size() == 1) + } else if (items.size() == 1) { return asBool(items.get(0)); - else - throw new PathEngineException("Unable to evaluate as a boolean: "+convertToString(items)); + } else { + throw makeException(I18nConstants.FHIRPATH_UNABLE_BOOLEAN, convertToString(items)); + } } private Equality asBoolFromInt(String s) { @@ -4594,44 +4881,47 @@ public class FHIRPathEngine { private Equality asBoolFromDec(String s) { try { BigDecimal d = new BigDecimal(s); - if (d.compareTo(BigDecimal.ZERO) == 0) + if (d.compareTo(BigDecimal.ZERO) == 0) { return Equality.False; - else if (d.compareTo(BigDecimal.ONE) == 0) + } else if (d.compareTo(BigDecimal.ONE) == 0) { return Equality.True; - else + } else { return Equality.Null; + } } catch (Exception e) { return Equality.Null; } } private Equality asBool(Base item) { - if (item instanceof BooleanType) + if (item instanceof BooleanType) { return boolToTriState(((BooleanType) item).booleanValue()); - else if (item.isBooleanPrimitive()) { - if (Utilities.existsInList(item.primitiveValue(), "true")) + } else if (item.isBooleanPrimitive()) { + if (Utilities.existsInList(item.primitiveValue(), "true")) { return Equality.True; - else if (Utilities.existsInList(item.primitiveValue(), "false")) + } else if (Utilities.existsInList(item.primitiveValue(), "false")) { return Equality.False; - else + } else { return Equality.Null; - } else if (item instanceof IntegerType || Utilities.existsInList(item.fhirType(), "integer", "positiveint", "unsignedInt")) + } + } else if (item instanceof IntegerType || Utilities.existsInList(item.fhirType(), "integer", "positiveint", "unsignedInt")) { return asBoolFromInt(item.primitiveValue()); - else if (item instanceof DecimalType || Utilities.existsInList(item.fhirType(), "decimal")) + } else if (item instanceof DecimalType || Utilities.existsInList(item.fhirType(), "decimal")) { return asBoolFromDec(item.primitiveValue()); - else if (Utilities.existsInList(item.fhirType(), FHIR_TYPES_STRING)) { - if (Utilities.existsInList(item.primitiveValue(), "true", "t", "yes", "y")) + } else if (Utilities.existsInList(item.fhirType(), FHIR_TYPES_STRING)) { + if (Utilities.existsInList(item.primitiveValue(), "true", "t", "yes", "y")) { return Equality.True; - else if (Utilities.existsInList(item.primitiveValue(), "false", "f", "no", "n")) + } else if (Utilities.existsInList(item.primitiveValue(), "false", "f", "no", "n")) { return Equality.False; - else if (Utilities.isInteger(item.primitiveValue())) + } else if (Utilities.isInteger(item.primitiveValue())) { return asBoolFromInt(item.primitiveValue()); - else if (Utilities.isDecimal(item.primitiveValue(), true)) + } else if (Utilities.isDecimal(item.primitiveValue(), true)) { return asBoolFromDec(item.primitiveValue()); - else + } else { return Equality.Null; + } } - return Equality.Null; + return Equality.Null; } private Equality boolToTriState(boolean b) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index c4d793e88..7c3d3a5bd 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -523,4 +523,48 @@ public class I18nConstants { public static final String VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL = "VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL"; public static final String ERROR_GENERATING_SNAPSHOT = "ERROR_GENERATING_SNAPSHOT"; public static final String SNAPSHOT_EXISTING_PROBLEM = "SNAPSHOT_EXISTING_PROBLEM"; + public static final String FHIRPATH_LOCATION = "FHIRPATH_LOCATION"; + public static final String FHIRPATH_UNKNOWN_CONTEXT = "FHIRPATH_UNKNOWN_CONTEXT"; + public static final String FHIRPATH_UNKNOWN_CONTEXT_ELEMENT = "FHIRPATH_UNKNOWN_CONTEXT_ELEMENT"; + public static final String FHIRPATH_ALIAS_COLLECTION = "FHIRPATH_ALIAS_COLLECTION"; + public static final String FHIRPATH_UNKNOWN_NAME = "FHIRPATH_UNWKNOWN_NAME"; + public static final String FHIRPATH_UNKNOWN_CONSTANT = "FHIRPATH_UNKNOWN_CONSTANT"; + public static final String FHIRPATH_CANNOT_USE = "FHIRPATH_CANNOT_USE"; + public static final String FHIRPATH_CANT_COMPARE = "FHIRPATH_CANT_COMPARE"; + public static final String FHIRPATH_LEFT_VALUE_PLURAL = "FHIRPATH_LEFT_VALUE_PLURAL"; + public static final String FHIRPATH_LEFT_VALUE_WRONG_TYPE = "FHIRPATH_LEFT_VALUE_WRONG_TYPE"; + public static final String FHIRPATH_RIGHT_VALUE_PLURAL = "FHIRPATH_RIGHT_VALUE_PLURAL"; + public static final String FHIRPATH_RIGHT_VALUE_WRONG_TYPE = "FHIRPATH_RIGHT_VALUE_WRONG_TYPE"; + public static final String FHIRPATH_OP_INCOMPATIBLE = "FHIRPATH_OP_INCOMPATIBLE"; + public static final String FHIRPATH_HO_HOST_SERVICES = "FHIRPATH_HO_HOST_SERVICES"; + public static final String FHIRPATH_WRONG_PARAM_TYPE = "FHIRPATH_WRONG_PARAM_TYPE"; + public static final String FHIRPATH_ORDERED_ONLY = "FHIRPATH_ORDERED_ONLY"; + public static final String FHIRPATH_REFERENCE_ONLY = "FHIRPATH_ORDERED_ONLY"; + public static final String FHIRPATH_CODED_ONLY = "FHIRPATH_CODED_ONLY"; + public static final String FHIRPATH_STRING_ONLY = "FHIRPATH_STRING_ONLY"; + public static final String FHIRPATH_PRIMITIVE_ONLY = "FHIRPATH_PRIMITIVE_ONLY"; + public static final String FHIRPATH_NO_COLLECTION = "FHIRPATH_NO_COLLECTION"; + public static final String FHIRPATH_NOT_IMPLEMENTED = "FHIRPATH_NOT_IMPLEMENTED"; + public static final String FHIRPATH_PARAM_WRONG = "FHIRPATH_PARAM_WRONG"; + public static final String FHIRPATH_CHECK_FAILED = "FHIRPATH_CHECK_FAILED"; + public static final String FHIRPATH_NO_TYPE = "FHIRPATH_NO_TYPE"; + public static final String FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED = "FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED"; + public static final String FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND = "FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND"; + public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE = "FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE"; + public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES = "FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES"; + public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE = "FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE"; + public static final String FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET = "FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET"; + public static final String FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND = "FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND"; + public static final String FHIRPATH_DISCRIMINATOR_TYPE_NONE = "FHIRPATH_DISCRIMINATOR_TYPE_NONE"; + public static final String FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE = "FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE"; + public static final String FHIRPATH_DISCRIMINATOR_NO_CODE = "FHIRPATH_DISCRIMINATOR_NO_CODE"; + public static final String FHIRPATH_DISCRIMINATOR_BAD_NAME = "FHIRPATH_DISCRIMINATOR_BAD_NAME"; + public static final String FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP = "FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP"; + public static final String FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST = "FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST"; + public static final String FHIRPATH_DISCRIMINATOR_CANT_FIND = "FHIRPATH_DISCRIMINATOR_CANT_FIND"; + public static final String FHIRPATH_DISCRIMINATOR_NOTYPE = "FHIRPATH_DISCRIMINATOR_NOTYPE"; + public static final String FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES = "FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES"; + public static final String FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES = "FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES"; + public static final String FHIRPATH_UNABLE_BOOLEAN = "FHIRPATH_UNABLE_BOOLEAN"; } + diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 6312c2f33..f78bd128f 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -524,3 +524,45 @@ VALIDATION_VAL_PROFILE_SIGNPOST_META = Validate resource against profile {0} - l VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL = Validate resource against profile {0} - a global profile in {1} ERROR_GENERATING_SNAPSHOT = Error generating Snapshot: {0} (this usually arises from a problem in the differential) SNAPSHOT_EXISTING_PROBLEM = The generated snapshot has a different number of elements {1} that the originally provided snapshot {0} +FHIRPATH_LOCATION = (at {0}) +FHIRPATH_UNKNOWN_CONTEXT = Unknown context evaluating FHIRPath expression: {0} +FHIRPATH_UNKNOWN_CONTEXT_ELEMENT = Unknown context element evaluating FHIRPath expression: {0} +FHIRPATH_ALIAS_COLLECTION = Attempt to alias a collection, not a singleton evaluating FHIRPath expression +FHIRPATH_UNKNOWN_NAME = Error evaluating FHIRPath expression: The name {0} is not valid for any of the possible types: {2} +FHIRPATH_UNKNOWN_CONSTANT = Error evaluating FHIRPath expression: Invalid FHIR Constant {0} +FHIRPATH_CANNOT_USE = Error evaluating FHIRPath expression: Cannot use {0} in this context because {1} +FHIRPATH_CANT_COMPARE = Error evaluating FHIRPath expression: Unable to compare values of type {0} and {1} +FHIRPATH_LEFT_VALUE_PLURAL = Error evaluating FHIRPath expression: left operand to {0} has more than one value +FHIRPATH_LEFT_VALUE_WRONG_TYPE = Error evaluating FHIRPath expression: left operand to {0} has the wrong type {1} +FHIRPATH_RIGHT_VALUE_PLURAL = Error evaluating FHIRPath expression: right operand to {0} has more than one value +FHIRPATH_RIGHT_VALUE_WRONG_TYPE = Error evaluating FHIRPath expression: right operand to {0} has the wrong type {1} +FHIRPATH_OP_INCOMPATIBLE = Error evaluating FHIRPath expression {0}: left and right operand have incompatible or illegal types ({1}, {2}) +FHIRPATH_HO_HOST_SERVICES = Internal Error evaluating FHIRPath expression: No host services are provided ({0}) +FHIRPATH_WRONG_PARAM_TYPE = Error evaluating FHIRPath expression: The parameter type {2} is not legal for {0} parameter {1}. expecting {3} +FHIRPATH_ORDERED_ONLY = Error evaluating FHIRPath expression: The function {0} can only be used on ordered collections +FHIRPATH_REFERENCE_ONLY = Error evaluating FHIRPath expression: The function {0} can only be used on ordered string, uri, canonical or Reference but found {1} +FHIRPATH_CODED_ONLY = Error evaluating FHIRPath expression: The function {0} can only be used on ordered string, code, uri, Coding, CodeableConcept but found {1} +FHIRPATH_STRING_ONLY = Error evaluating FHIRPath expression: The function {0} can only be used on ordered string, uri, code, id but found {1} +FHIRPATH_NO_COLLECTION = Error evaluating FHIRPath expression: The function {0} can only be used on a singleton value but found {1} +FHIRPATH_NOT_IMPLEMENTED = Error evaluating FHIRPath expression: The function {0} is not implemented +FHIRPATH_PARAM_WRONG = Error evaluating FHIRPath expression: The expression type {0} is not supported for parameter {1} on function {2} +FHIRPATH_CHECK_FAILED = Error evaluating FHIRPath expression: The check {0} failed +FHIRPATH_NO_TYPE = Error evaluating FHIRPath expression: The type "{0}" is unknown or not supported at {1} +FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED = Error in discriminator at {0}: found a sliced element while resolving the fixed value for one of the slices +FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND = Problem with use of resolve() - profile {0} on {1} could not be resolved +FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE = illegal use of resolve() in discriminator - no type on element {0} +FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES = illegal use of resolve() in discriminator - Multiple possible types on {0} +FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE = illegal use of resolve() in discriminator - type on {0} is not Reference {1} +FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET = illegal use of resolve() in discriminator - Multiple possible target type profiles on {0} +FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND = Problem with use of resolve() - profile {0} on {1} could not be resolved +FHIRPATH_DISCRIMINATOR_TYPE_NONE = illegal use of ofType() in discriminator - no type on element {0} +FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE = illegal use of ofType() in discriminator - Multiple possible types on {0} +FHIRPATH_DISCRIMINATOR_NO_CODE = illegal use of ofType() in discriminator - Type has no code on {0} +FHIRPATH_DISCRIMINATOR_BAD_NAME = illegal function name {0}() in discriminator +FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP = illegal expression syntax in discriminator (group) +FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST = illegal expression syntax in discriminator (const) +FHIRPATH_DISCRIMINATOR_CANT_FIND = Unable to resolve discriminator in definitions: {0} +FHIRPATH_DISCRIMINATOR_NOTYPE = Error in discriminator at {0}: no children, no type +FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES = Error in discriminator at {0}: no children, multiple types +FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES = Error in discriminator at {0}: no children, multiple type profiles +FHIRPATH_UNABLE_BOOLEAN = Unable to evaluate as a boolean: {0}