diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/R5ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/R5ToR5Loader.java deleted file mode 100644 index b369b0375..000000000 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/R5ToR5Loader.java +++ /dev/null @@ -1,180 +0,0 @@ -package org.hl7.fhir.convertors; - -/*- - * #%L - * org.hl7.fhir.convertors - * %% - * Copyright (C) 2014 - 2019 Health Level 7 - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.formats.JsonParser; -import org.hl7.fhir.r5.formats.XmlParser; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.context.SimpleWorkerContext.IContextResourceLoader; -import org.hl7.fhir.r5.model.Bundle; -import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.r5.model.Bundle.BundleType; -import org.hl7.fhir.r5.model.CanonicalResource; -import org.hl7.fhir.r5.model.CanonicalType; -import org.hl7.fhir.r5.model.CodeSystem; -import org.hl7.fhir.r5.model.ElementDefinition; -import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; -import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; -import org.hl7.fhir.r5.model.UriType; -import org.hl7.fhir.r5.model.ValueSet; - -/** - * This loader doesn't really do anything, but it's defined for structural consistency - * - * @author graha - * - */ -public class R5ToR5Loader extends BaseLoader implements IContextResourceLoader, VersionConvertorAdvisor50 { - - public R5ToR5Loader(String[] types) { - super(types); - } - - private List cslist = new ArrayList<>(); - private boolean patchUrls; - private boolean killPrimitives;; - - @Override - public Bundle loadBundle(InputStream stream, boolean isJson) throws FHIRException, IOException { - Resource r5 = null; - if (isJson) - r5 = new JsonParser().parse(stream); - else - r5 = new XmlParser().parse(stream); - - Bundle b; - if (r5 instanceof Bundle) - b = (Bundle) r5; - else { - b = new Bundle(); - b.setId(UUID.randomUUID().toString().toLowerCase()); - b.setType(BundleType.COLLECTION); - b.addEntry().setResource(r5).setFullUrl(r5 instanceof CanonicalResource ? ((CanonicalResource) r5).getUrl() : null); - } - for (CodeSystem cs : cslist) { - BundleEntryComponent be = b.addEntry(); - be.setFullUrl(cs.getUrl()); - be.setResource(cs); - } - if (killPrimitives) { - List remove = new ArrayList(); - for (BundleEntryComponent be : b.getEntry()) { - if (be.hasResource() && be.getResource() instanceof StructureDefinition) { - StructureDefinition sd = (StructureDefinition) be.getResource(); - if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) - remove.add(be); - } - } - b.getEntry().removeAll(remove); - } - if (patchUrls) { - for (BundleEntryComponent be : b.getEntry()) { - if (be.hasResource() && be.getResource() instanceof StructureDefinition) { - StructureDefinition sd = (StructureDefinition) be.getResource(); - sd.setUrl(sd.getUrl().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/")); - sd.addExtension().setUrl("http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace").setValue(new UriType("http://hl7.org/fhir")); - for (ElementDefinition ed : sd.getSnapshot().getElement()) - patchUrl(ed); - for (ElementDefinition ed : sd.getDifferential().getElement()) - patchUrl(ed); - } - } - } - return b; - } - - private void patchUrl(ElementDefinition ed) { - for (TypeRefComponent tr : ed.getType()) { - for (CanonicalType s : tr.getTargetProfile()) { - s.setValue(s.getValue().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/")); - } - for (CanonicalType s : tr.getProfile()) { - s.setValue(s.getValue().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/")); - } - } - } - - @Override - public boolean ignoreEntry(BundleEntryComponent src) { - return false; - } - - @Override - public org.hl7.fhir.dstu2.model.Resource convertR2(org.hl7.fhir.r5.model.Resource resource) throws FHIRException { - return null; - } - - @Override - public org.hl7.fhir.dstu2016may.model.Resource convertR2016May(org.hl7.fhir.r5.model.Resource resource) throws FHIRException { - return null; - } - - @Override - public org.hl7.fhir.r4.model.Resource convertR4(org.hl7.fhir.r5.model.Resource resource) throws FHIRException { - return null; - } - - @Override - public void handleCodeSystem(CodeSystem cs, ValueSet vs) { - cs.setId(vs.getId()); - cs.setValueSet(vs.getUrl()); - cslist.add(cs); - - } - - @Override - public CodeSystem getCodeSystem(ValueSet src) { - return null; - } - - public boolean isPatchUrls() { - return patchUrls; - } - - public R5ToR5Loader setPatchUrls(boolean patchUrls) { - this.patchUrls = patchUrls; - return this; - } - - public boolean isKillPrimitives() { - return killPrimitives; - } - - public R5ToR5Loader setKillPrimitives(boolean killPrimitives) { - this.killPrimitives = killPrimitives; - return this; - } - - @Override - public org.hl7.fhir.dstu3.model.Resource convertR3(org.hl7.fhir.r5.model.Resource resource) throws FHIRException { - return null; - } - -} diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/MedicationDispense10_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/MedicationDispense10_50.java index 7aafac6f7..79bdd9196 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/MedicationDispense10_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/MedicationDispense10_50.java @@ -4,6 +4,7 @@ import org.hl7.fhir.convertors.VersionConvertor_10_50; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.model.Dosage; import org.hl7.fhir.r5.model.Dosage.DosageDoseAndRateComponent; +import org.hl7.fhir.r5.model.MedicationDispense.MedicationDispenseStatusCodesEnumFactory; public class MedicationDispense10_50 { @@ -127,7 +128,7 @@ public class MedicationDispense10_50 { public static org.hl7.fhir.r5.model.Enumeration convertMedicationDispenseStatus(org.hl7.fhir.dstu2.model.Enumeration src) throws FHIRException { if (src == null) return null; - org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration(); + org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration<>(new MedicationDispenseStatusCodesEnumFactory()); VersionConvertor_10_50.copyElement(src, tgt); switch(src.getValue()) { case COMPLETED: diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/MedicationAdministration30_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/MedicationAdministration30_50.java index 0637cebce..061b72a28 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/MedicationAdministration30_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/MedicationAdministration30_50.java @@ -3,6 +3,7 @@ package org.hl7.fhir.convertors.conv30_50; import org.hl7.fhir.convertors.VersionConvertor_30_50; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.model.CodeableReference; +import org.hl7.fhir.r5.model.MedicationAdministration.MedicationAdministrationStatusCodesEnumFactory; public class MedicationAdministration30_50 { @@ -139,7 +140,7 @@ public class MedicationAdministration30_50 { static public org.hl7.fhir.r5.model.Enumeration convertMedicationAdministrationStatus(org.hl7.fhir.dstu3.model.Enumeration src) { if (src == null) return null; - org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration(); + org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration<>(new MedicationAdministrationStatusCodesEnumFactory()); VersionConvertor_30_50.copyElement(src, tgt); tgt.setValue(org.hl7.fhir.r5.model.MedicationAdministration.MedicationAdministrationStatusCodes.fromCode(src.getValueAsString())); return tgt; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationAdministration40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationAdministration40_50.java index eeff0d742..f5e09ddd3 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationAdministration40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationAdministration40_50.java @@ -25,6 +25,7 @@ import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r5.model.CodeableReference; import org.hl7.fhir.r5.model.Enumeration; import org.hl7.fhir.r5.model.MedicationAdministration.MedicationAdministrationStatusCodes; +import org.hl7.fhir.r5.model.MedicationAdministration.MedicationAdministrationStatusCodesEnumFactory; /* Copyright (c) 2011+, HL7, Inc. @@ -141,7 +142,7 @@ public class MedicationAdministration40_50 extends VersionConvertor_40_50 { private static Enumeration convertMedicationAdministrationStatus(CodeType src) { if (src == null) return null; - Enumeration tgt = new Enumeration(); + Enumeration tgt = new Enumeration<>(new MedicationAdministrationStatusCodesEnumFactory()); copyElement(src, tgt); tgt.setValue(MedicationAdministrationStatusCodes.fromCode(src.getCode())); return tgt; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationDispense40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationDispense40_50.java index 1fc91144a..421bc5b71 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationDispense40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationDispense40_50.java @@ -23,6 +23,7 @@ import org.hl7.fhir.convertors.VersionConvertor_40_50; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r5.model.MedicationDispense.MedicationDispenseStatusCodes; +import org.hl7.fhir.r5.model.MedicationDispense.MedicationDispenseStatusCodesEnumFactory; /* Copyright (c) 2011+, HL7, Inc. @@ -162,7 +163,7 @@ public class MedicationDispense40_50 extends VersionConvertor_40_50 { private static org.hl7.fhir.r5.model.Enumeration convertMedicationStatus(org.hl7.fhir.r4.model.CodeType src) { if (src == null) return null; - org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration(); + org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration<>(new MedicationDispenseStatusCodesEnumFactory()); copyElement(src, tgt); if (src.hasCode()) tgt.setValue(MedicationDispenseStatusCodes.fromCode(src.getCode())); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationKnowledge40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationKnowledge40_50.java index dd4a089e6..56180669c 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationKnowledge40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/MedicationKnowledge40_50.java @@ -24,6 +24,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r5.model.Enumeration; import org.hl7.fhir.r5.model.MedicationKnowledge.MedicationKnowledgeStatusCodes; +import org.hl7.fhir.r5.model.MedicationKnowledge.MedicationKnowledgeStatusCodesEnumFactory; /* Copyright (c) 2011+, HL7, Inc. @@ -148,7 +149,7 @@ public class MedicationKnowledge40_50 extends VersionConvertor_40_50 { private static Enumeration convertMedicationKnowledgeStatus(CodeType src) { if (src == null) return null; - org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration(); + org.hl7.fhir.r5.model.Enumeration tgt = new org.hl7.fhir.r5.model.Enumeration<>(new MedicationKnowledgeStatusCodesEnumFactory()); copyElement(src, tgt); tgt.setValue(MedicationKnowledgeStatusCodes.fromCode(src.getCode())); return tgt; diff --git a/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/BaseWorkerContext.java b/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/BaseWorkerContext.java index 59024f9a3..e7a213e0d 100644 --- a/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/BaseWorkerContext.java +++ b/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/BaseWorkerContext.java @@ -23,11 +23,15 @@ package org.hl7.fhir.dstu2.utils; import java.io.FileNotFoundException; import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Objects; +import java.util.ResourceBundle; import java.util.Set; import org.hl7.fhir.dstu2.model.BooleanType; @@ -73,6 +77,8 @@ public abstract class BaseWorkerContext implements IWorkerContext { // private ValueSetExpansionCache expansionCache; // protected FHIRToolingClient txServer; + private Locale locale; + private ResourceBundle i18Nmessages; @Override public ValueSet fetchCodeSystem(String system) { @@ -402,4 +408,37 @@ public abstract class BaseWorkerContext implements IWorkerContext { return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+typeName); } + @Override + public Locale getLocale() { + if (Objects.nonNull(locale)){ + return locale; + } else { + return Locale.US; + } + } + + @Override + public void setLocale(Locale locale) { + this.locale = locale; + setValidationMessageLanguage(getLocale()); + } + + @Override + public String formatMessage(String theMessage, Object... theMessageArguments) { + String message = theMessage; + if (Objects.nonNull(i18Nmessages) && i18Nmessages.containsKey(theMessage)) { + if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) { + message = MessageFormat.format(i18Nmessages.getString(theMessage), theMessageArguments); + } else { + message = i18Nmessages.getString(theMessage); + } + } + return message; + } + + @Override + public void setValidationMessageLanguage(Locale locale) { + i18Nmessages = ResourceBundle.getBundle("Messages", locale ); + } + } diff --git a/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/IWorkerContext.java b/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/IWorkerContext.java index c566a64f8..ddf1dd822 100644 --- a/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/IWorkerContext.java +++ b/org.hl7.fhir.dstu2/src/main/java/org/hl7/fhir/dstu2/utils/IWorkerContext.java @@ -23,6 +23,7 @@ package org.hl7.fhir.dstu2.utils; import java.util.List; +import java.util.Locale; import org.hl7.fhir.dstu2.formats.IParser; import org.hl7.fhir.dstu2.formats.ParserType; import org.hl7.fhir.dstu2.model.CodeableConcept; @@ -208,7 +209,15 @@ public interface IWorkerContext { * @return */ public ValueSetExpansionComponent expandVS(ConceptSetComponent inc); - + + Locale getLocale(); + + void setLocale(Locale locale); + + String formatMessage(String theMessage, Object... theMessageArguments); + + void setValidationMessageLanguage(Locale locale); + public class ValidationResult { private ConceptDefinitionComponent definition; private IssueSeverity severity; diff --git a/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/BaseWorkerContext.java b/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/BaseWorkerContext.java index f56158e9d..262178207 100644 --- a/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/BaseWorkerContext.java +++ b/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/BaseWorkerContext.java @@ -23,11 +23,15 @@ package org.hl7.fhir.dstu2016may.utils; import java.io.FileNotFoundException; import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Objects; +import java.util.ResourceBundle; import java.util.Set; import org.hl7.fhir.dstu2016may.model.BooleanType; @@ -75,6 +79,8 @@ public abstract class BaseWorkerContext implements IWorkerContext { protected FHIRToolingClient txServer; private Bundle bndCodeSystems; + private Locale locale; + private ResourceBundle i18Nmessages; @Override public CodeSystem fetchCodeSystem(String system) { @@ -441,5 +447,37 @@ public abstract class BaseWorkerContext implements IWorkerContext { return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+typeName); } + @Override + public Locale getLocale() { + if (Objects.nonNull(locale)){ + return locale; + } else { + return Locale.US; + } + } + + @Override + public void setLocale(Locale locale) { + this.locale = locale; + setValidationMessageLanguage(getLocale()); + } + + @Override + public String formatMessage(String theMessage, Object... theMessageArguments) { + String message = theMessage; + if (Objects.nonNull(i18Nmessages) && i18Nmessages.containsKey(theMessage)) { + if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) { + message = MessageFormat.format(i18Nmessages.getString(theMessage), theMessageArguments); + } else { + message = i18Nmessages.getString(theMessage); + } + } + return message; + } + + @Override + public void setValidationMessageLanguage(Locale locale) { + i18Nmessages = ResourceBundle.getBundle("Messages", locale ); + } } diff --git a/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/IWorkerContext.java b/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/IWorkerContext.java index d9e91b6ee..fa96c4915 100644 --- a/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/IWorkerContext.java +++ b/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/utils/IWorkerContext.java @@ -22,6 +22,7 @@ package org.hl7.fhir.dstu2016may.utils; import java.util.List; +import java.util.Locale; import java.util.Set; import org.hl7.fhir.dstu2016may.formats.IParser; @@ -204,7 +205,15 @@ public interface IWorkerContext { * @return */ public ValueSetExpansionComponent expandVS(ConceptSetComponent inc); - + + Locale getLocale(); + + void setLocale(Locale locale); + + String formatMessage(String theMessage, Object... theMessageArguments); + + void setValidationMessageLanguage(Locale locale); + public class ValidationResult { private ConceptDefinitionComponent definition; private IssueSeverity severity; diff --git a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/BaseWorkerContext.java b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/BaseWorkerContext.java index 8fbcee29a..2ba664936 100644 --- a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/BaseWorkerContext.java +++ b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/BaseWorkerContext.java @@ -9,9 +9,9 @@ package org.hl7.fhir.dstu3.context; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,11 +27,15 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Objects; +import java.util.ResourceBundle; import java.util.Set; import ca.uhn.fhir.rest.api.Constants; @@ -106,7 +110,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { protected ValueSetExpanderFactory expansionCache = new ValueSetExpansionCache(this); protected boolean cacheValidation; // if true, do an expansion and cache the expansion private Set failed = new HashSet(); // value sets for which we don't try to do expansion, since the first attempt to get a comprehensive expansion was not successful - protected Map> validationCache = new HashMap>(); + protected Map> validationCache = new HashMap>(); protected String tsServer; protected String validationCachePath; protected String name; @@ -122,6 +126,8 @@ public abstract class BaseWorkerContext implements IWorkerContext { private int expandCodesLimit = 1000; protected ILoggingService logger; protected ExpansionProfile expProfile; + private Locale locale; + private ResourceBundle i18Nmessages; public Map getCodeSystems() { return codeSystems; @@ -156,8 +162,9 @@ public abstract class BaseWorkerContext implements IWorkerContext { } public void seeExtensionDefinition(String url, StructureDefinition ed) throws Exception { - if (extensionDefinitions.get(ed.getUrl()) != null) + if (extensionDefinitions.get(ed.getUrl()) != null) { throw new Exception("duplicate extension definition: " + ed.getUrl()); + } extensionDefinitions.put(ed.getId(), ed); extensionDefinitions.put(url, ed); extensionDefinitions.put(ed.getUrl(), ed); @@ -166,27 +173,31 @@ public abstract class BaseWorkerContext implements IWorkerContext { public void dropExtensionDefinition(String id) { StructureDefinition sd = extensionDefinitions.get(id); extensionDefinitions.remove(id); - if (sd!= null) + if (sd != null) { extensionDefinitions.remove(sd.getUrl()); + } } public void seeQuestionnaire(String url, Questionnaire theQuestionnaire) throws Exception { - if (questionnaires.get(theQuestionnaire.getId()) != null) - throw new Exception("duplicate extension definition: "+theQuestionnaire.getId()); + if (questionnaires.get(theQuestionnaire.getId()) != null) { + throw new Exception("duplicate extension definition: " + theQuestionnaire.getId()); + } questionnaires.put(theQuestionnaire.getId(), theQuestionnaire); questionnaires.put(url, theQuestionnaire); } public void seeOperation(OperationDefinition opd) throws Exception { - if (operations.get(opd.getUrl()) != null) - throw new Exception("duplicate extension definition: "+opd.getUrl()); + if (operations.get(opd.getUrl()) != null) { + throw new Exception("duplicate extension definition: " + opd.getUrl()); + } operations.put(opd.getUrl(), opd); operations.put(opd.getId(), opd); } public void seeValueSet(String url, ValueSet vs) throws Exception { - if (valueSets.containsKey(vs.getUrl()) && !allowLoadingDuplicates) - throw new Exception("Duplicate value set "+vs.getUrl()); + if (valueSets.containsKey(vs.getUrl()) && !allowLoadingDuplicates) { + throw new Exception("Duplicate value set " + vs.getUrl()); + } valueSets.put(vs.getId(), vs); valueSets.put(url, vs); valueSets.put(vs.getUrl(), vs); @@ -195,13 +206,15 @@ public abstract class BaseWorkerContext implements IWorkerContext { public void dropValueSet(String id) { ValueSet vs = valueSets.get(id); valueSets.remove(id); - if (vs != null) + if (vs != null) { valueSets.remove(vs.getUrl()); + } } public void seeCodeSystem(String url, CodeSystem cs) throws FHIRException { - if (codeSystems.containsKey(cs.getUrl()) && !allowLoadingDuplicates) - throw new FHIRException("Duplicate code system "+cs.getUrl()); + if (codeSystems.containsKey(cs.getUrl()) && !allowLoadingDuplicates) { + throw new FHIRException("Duplicate code system " + cs.getUrl()); + } codeSystems.put(cs.getId(), cs); codeSystems.put(url, cs); codeSystems.put(cs.getUrl(), cs); @@ -210,13 +223,15 @@ public abstract class BaseWorkerContext implements IWorkerContext { public void dropCodeSystem(String id) { CodeSystem cs = codeSystems.get(id); codeSystems.remove(id); - if (cs != null) + if (cs != null) { codeSystems.remove(cs.getUrl()); + } } public void seeProfile(String url, StructureDefinition p) throws Exception { - if (profiles.containsKey(p.getUrl())) - throw new Exception("Duplicate Profile "+p.getUrl()); + if (profiles.containsKey(p.getUrl())) { + throw new Exception("Duplicate Profile " + p.getUrl()); + } profiles.put(p.getId(), p); profiles.put(url, p); profiles.put(p.getUrl(), p); @@ -225,37 +240,43 @@ public abstract class BaseWorkerContext implements IWorkerContext { public void dropProfile(String id) { StructureDefinition sd = profiles.get(id); profiles.remove(id); - if (sd!= null) + if (sd != null) { profiles.remove(sd.getUrl()); + } } @Override public CodeSystem fetchCodeSystem(String system) { return codeSystems.get(system); - } + } @Override public boolean supportsSystem(String system) throws TerminologyServiceException { - if (codeSystems.containsKey(system)) + if (codeSystems.containsKey(system)) { return true; - else if (nonSupportedCodeSystems.contains(system)) + } else if (nonSupportedCodeSystems.contains(system)) { return false; - else if (system.startsWith("http://example.org") || system.startsWith("http://acme.com") || system.startsWith("http://hl7.org/fhir/valueset-") || system.startsWith("urn:oid:")) + } else if (system.startsWith("http://example.org") || system.startsWith("http://acme.com") + || system.startsWith("http://hl7.org/fhir/valueset-") || system.startsWith("urn:oid:")) { return false; - else { - if (noTerminologyServer) + } else { + if (noTerminologyServer) { return false; + } if (bndCodeSystems == null) { try { - tlog("Terminology server: Check for supported code systems for "+system); - bndCodeSystems = txServer.fetchFeed(txServer.getAddress()+"/CodeSystem?content-mode=not-present&_summary=true&_count=1000"); + tlog("Terminology server: Check for supported code systems for " + system); + bndCodeSystems = txServer.fetchFeed(txServer.getAddress() + + "/CodeSystem?content-mode=not-present&_summary=true&_count=1000"); } catch (Exception e) { if (canRunWithoutTerminology) { noTerminologyServer = true; - log("==============!! Running without terminology server !!============== ("+e.getMessage()+")"); + log("==============!! Running without terminology server !!============== (" + e + .getMessage() + ")"); return false; - } else + } else { throw new TerminologyServiceException(e); + } } } if (bndCodeSystems != null) { @@ -266,18 +287,20 @@ public abstract class BaseWorkerContext implements IWorkerContext { } } } - if (codeSystems.containsKey(system)) + if (codeSystems.containsKey(system)) { return true; + } } nonSupportedCodeSystems.add(system); return false; } private void log(String message) { - if (logger != null) + if (logger != null) { logger.logMessage(message); - else + } else { System.out.println(message); + } } @Override @@ -288,14 +311,17 @@ public abstract class BaseWorkerContext implements IWorkerContext { } String cacheFn = null; if (cache != null) { - cacheFn = Utilities.path(cache, determineCacheId(vs, heirarchical)+".json"); - if (new File(cacheFn).exists()) + cacheFn = Utilities.path(cache, determineCacheId(vs, heirarchical) + ".json"); + if (new File(cacheFn).exists()) { return loadFromCache(vs.copy(), cacheFn); + } } if (cacheOk && vs.hasUrl()) { - if (expProfile == null) + if (expProfile == null) { throw new Exception("No ExpansionProfile provided"); - ValueSetExpansionOutcome vse = expansionCache.getExpander().expand(vs, expProfile.setExcludeNested(!heirarchical)); + } + ValueSetExpansionOutcome vse = expansionCache.getExpander() + .expand(vs, expProfile.setExcludeNested(!heirarchical)); if (vse.getValueset() != null) { if (cache != null) { FileOutputStream s = new FileOutputStream(cacheFn); @@ -309,7 +335,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { if (cacheFn != null) { if (res.getValueset() != null) { saveToCache(res.getValueset(), cacheFn); - } else { + } else { OperationOutcome oo = new OperationOutcome(); oo.addIssue().getDetails().setText(res.getError()); saveToCache(oo, cacheFn); @@ -318,19 +344,27 @@ public abstract class BaseWorkerContext implements IWorkerContext { return res; } } catch (NoTerminologyServiceException e) { - return new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.NOSERVICE); + return new ValueSetExpansionOutcome( + e.getMessage() == null ? e.getClass().getName() : e.getMessage(), + TerminologyServiceErrorClass.NOSERVICE); } catch (Exception e) { - return new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN); + return new ValueSetExpansionOutcome( + e.getMessage() == null ? e.getClass().getName() : e.getMessage(), + TerminologyServiceErrorClass.UNKNOWN); } } - private ValueSetExpansionOutcome loadFromCache(ValueSet vs, String cacheFn) throws FileNotFoundException, Exception { + private ValueSetExpansionOutcome loadFromCache(ValueSet vs, String cacheFn) + throws FileNotFoundException, Exception { JsonParser parser = new JsonParser(); Resource r = parser.parse(new FileInputStream(cacheFn)); - if (r instanceof OperationOutcome) - return new ValueSetExpansionOutcome(((OperationOutcome) r).getIssue().get(0).getDetails().getText(), TerminologyServiceErrorClass.UNKNOWN); - else { - vs.setExpansion(((ValueSet) r).getExpansion()); // because what is cached might be from a different value set + if (r instanceof OperationOutcome) { + return new ValueSetExpansionOutcome( + ((OperationOutcome) r).getIssue().get(0).getDetails().getText(), + TerminologyServiceErrorClass.UNKNOWN); + } else { + vs.setExpansion(((ValueSet) r) + .getExpansion()); // because what is cached might be from a different value set return new ValueSetExpansionOutcome(vs); } } @@ -346,7 +380,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { vsid.setCompose(vs.getCompose()); JsonParser parser = new JsonParser(); parser.setOutputStyle(OutputStyle.NORMAL); - ByteArrayOutputStream b = new ByteArrayOutputStream(); + ByteArrayOutputStream b = new ByteArrayOutputStream(); parser.compose(b, vsid); b.close(); String s = new String(b.toByteArray(), Constants.CHARSET_UTF8); @@ -358,7 +392,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { s = s + css; } } - s = s + "-"+Boolean.toString(heirarchical); + s = s + "-" + Boolean.toString(heirarchical); String r = Integer.toString(s.hashCode()); // TextFile.stringToFile(s, Utilities.path(cache, r+".id.json")); return r; @@ -371,11 +405,12 @@ public abstract class BaseWorkerContext implements IWorkerContext { csid.setVersion(cs.getVersion()); csid.setContent(cs.getContent()); csid.setHierarchyMeaning(CodeSystemHierarchyMeaning.GROUPEDBY); - for (ConceptDefinitionComponent cc : cs.getConcept()) + for (ConceptDefinitionComponent cc : cs.getConcept()) { csid.getConcept().add(processCSConcept(cc)); + } JsonParser parser = new JsonParser(); parser.setOutputStyle(OutputStyle.NORMAL); - ByteArrayOutputStream b = new ByteArrayOutputStream(); + ByteArrayOutputStream b = new ByteArrayOutputStream(); parser.compose(b, csid); b.close(); return new String(b.toByteArray(), Constants.CHARSET_UTF8); @@ -386,56 +421,69 @@ public abstract class BaseWorkerContext implements IWorkerContext { ConceptDefinitionComponent ccid = new ConceptDefinitionComponent(); ccid.setCode(cc.getCode()); ccid.setDisplay(cc.getDisplay()); - for (ConceptDefinitionComponent cci : cc.getConcept()) + for (ConceptDefinitionComponent cci : cc.getConcept()) { ccid.getConcept().add(processCSConcept(cci)); + } return ccid; } public ValueSetExpansionOutcome expandOnServer(ValueSet vs, String fn) throws Exception { - if (noTerminologyServer) - return new ValueSetExpansionOutcome("Error expanding ValueSet: running without terminology services", TerminologyServiceErrorClass.NOSERVICE); - if (expProfile == null) + if (noTerminologyServer) { + return new ValueSetExpansionOutcome( + "Error expanding ValueSet: running without terminology services", + TerminologyServiceErrorClass.NOSERVICE); + } + if (expProfile == null) { throw new Exception("No ExpansionProfile provided"); + } try { Map params = new HashMap(); - params.put("_limit", Integer.toString(expandCodesLimit )); + params.put("_limit", Integer.toString(expandCodesLimit)); params.put("_incomplete", "true"); - tlog("Terminology Server: $expand on "+getVSSummary(vs)); + tlog("Terminology Server: $expand on " + getVSSummary(vs)); ValueSet result = txServer.expandValueset(vs, expProfile.setIncludeDefinition(false), params); - return new ValueSetExpansionOutcome(result); + return new ValueSetExpansionOutcome(result); } catch (Exception e) { - return new ValueSetExpansionOutcome("Error expanding ValueSet \""+vs.getUrl()+": "+e.getMessage(), TerminologyServiceErrorClass.UNKNOWN); + return new ValueSetExpansionOutcome( + "Error expanding ValueSet \"" + vs.getUrl() + ": " + e.getMessage(), + TerminologyServiceErrorClass.UNKNOWN); } } private String getVSSummary(ValueSet vs) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (ConceptSetComponent cc : vs.getCompose().getInclude()) - b.append("Include "+getIncSummary(cc)); - for (ConceptSetComponent cc : vs.getCompose().getExclude()) - b.append("Exclude "+getIncSummary(cc)); + for (ConceptSetComponent cc : vs.getCompose().getInclude()) { + b.append("Include " + getIncSummary(cc)); + } + for (ConceptSetComponent cc : vs.getCompose().getExclude()) { + b.append("Exclude " + getIncSummary(cc)); + } return b.toString(); } private String getIncSummary(ConceptSetComponent cc) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (UriType vs : cc.getValueSet()) + for (UriType vs : cc.getValueSet()) { b.append(vs.asStringValue()); - String vsd = b.length() > 0 ? " where the codes are in the value sets ("+b.toString()+")" : ""; + } + String vsd = + b.length() > 0 ? " where the codes are in the value sets (" + b.toString() + ")" : ""; String system = cc.getSystem(); - if (cc.hasConcept()) - return Integer.toString(cc.getConcept().size())+" codes from "+system+vsd; + if (cc.hasConcept()) { + return Integer.toString(cc.getConcept().size()) + " codes from " + system + vsd; + } if (cc.hasFilter()) { String s = ""; for (ConceptSetFilterComponent f : cc.getFilter()) { - if (!Utilities.noString(s)) + if (!Utilities.noString(s)) { s = s + " & "; - s = s + f.getProperty()+" "+f.getOp().toCode()+" "+f.getValue(); + } + s = s + f.getProperty() + " " + f.getOp().toCode() + " " + f.getValue(); } - return "from "+system+" where "+s+vsd; + return "from " + system + " where " + s + vsd; } - return "All codes from "+system+vsd; + return "All codes from " + system + vsd; } private ValidationResult handleByCache(ValueSet vs, Coding coding, boolean tryCache) { @@ -445,14 +493,18 @@ public abstract class BaseWorkerContext implements IWorkerContext { cache = new HashMap(); validationCache.put(vs.getUrl(), cache); } - if (cache.containsKey(cacheId)) + if (cache.containsKey(cacheId)) { return cache.get(cacheId); - if (!tryCache) + } + if (!tryCache) { return null; - if (!cacheValidation) + } + if (!cacheValidation) { return null; - if (failed.contains(vs.getUrl())) + } + if (failed.contains(vs.getUrl())) { return null; + } ValueSetExpansionOutcome vse = expandVS(vs, true, false); if (vse.getValueset() == null || notcomplete(vse.getValueset())) { failed.add(vs.getUrl()); @@ -465,12 +517,17 @@ public abstract class BaseWorkerContext implements IWorkerContext { } private boolean notcomplete(ValueSet vs) { - if (!vs.hasExpansion()) + if (!vs.hasExpansion()) { return true; - if (!vs.getExpansion().getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/valueset-unclosed").isEmpty()) + } + if (!vs.getExpansion() + .getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/valueset-unclosed").isEmpty()) { return true; - if (!vs.getExpansion().getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/valueset-toocostly").isEmpty()) + } + if (!vs.getExpansion() + .getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/valueset-toocostly").isEmpty()) { return true; + } return false; } @@ -481,17 +538,23 @@ public abstract class BaseWorkerContext implements IWorkerContext { cache = new HashMap(); validationCache.put(vs.getUrl(), cache); } - if (cache.containsKey(cacheId)) + if (cache.containsKey(cacheId)) { return cache.get(cacheId); + } - if (validationCache.containsKey(vs.getUrl()) && validationCache.get(vs.getUrl()).containsKey(cacheId)) + if (validationCache.containsKey(vs.getUrl()) && validationCache.get(vs.getUrl()) + .containsKey(cacheId)) { return validationCache.get(vs.getUrl()).get(cacheId); - if (!tryCache) + } + if (!tryCache) { return null; - if (!cacheValidation) + } + if (!cacheValidation) { return null; - if (failed.contains(vs.getUrl())) + } + if (failed.contains(vs.getUrl())) { return null; + } ValueSetExpansionOutcome vse = expandVS(vs, true, false); if (vse.getValueset() == null || notcomplete(vse.getValueset())) { failed.add(vs.getUrl()); @@ -503,7 +566,8 @@ public abstract class BaseWorkerContext implements IWorkerContext { } private String cacheId(Coding coding) { - return "|"+coding.getSystem()+"|"+coding.getVersion()+"|"+coding.getCode()+"|"+coding.getDisplay(); + return "|" + coding.getSystem() + "|" + coding.getVersion() + "|" + coding.getCode() + "|" + + coding.getDisplay(); } private String cacheId(CodeableConcept cc) { @@ -511,18 +575,21 @@ public abstract class BaseWorkerContext implements IWorkerContext { for (Coding c : cc.getCoding()) { b.append("#"); b.append(cacheId(c)); - } + } return b.toString(); } - private ValidationResult verifyCodeExternal(ValueSet vs, Coding coding, boolean tryCache) throws Exception { + private ValidationResult verifyCodeExternal(ValueSet vs, Coding coding, boolean tryCache) + throws Exception { ValidationResult res = vs == null ? null : handleByCache(vs, coding, tryCache); - if (res != null) + if (res != null) { return res; + } Parameters pin = new Parameters(); pin.addParameter().setName("coding").setValue(coding); - if (vs != null) + if (vs != null) { pin.addParameter().setName("valueSet").setResource(vs); + } res = serverValidateCode(pin, vs == null); if (vs != null) { Map cache = validationCache.get(vs.getUrl()); @@ -531,10 +598,12 @@ public abstract class BaseWorkerContext implements IWorkerContext { return res; } - private ValidationResult verifyCodeExternal(ValueSet vs, CodeableConcept cc, boolean tryCache) throws Exception { + private ValidationResult verifyCodeExternal(ValueSet vs, CodeableConcept cc, boolean tryCache) + throws Exception { ValidationResult res = handleByCache(vs, cc, tryCache); - if (res != null) + if (res != null) { return res; + } Parameters pin = new Parameters(); pin.addParameter().setName("codeableConcept").setValue(cc); pin.addParameter().setName("valueSet").setResource(vs); @@ -545,18 +614,23 @@ public abstract class BaseWorkerContext implements IWorkerContext { } private ValidationResult serverValidateCode(Parameters pin, boolean doCache) throws Exception { - if (noTerminologyServer) + if (noTerminologyServer) { return new ValidationResult(null, null, TerminologyServiceErrorClass.NOSERVICE); + } String cacheName = doCache ? generateCacheName(pin) : null; ValidationResult res = loadFromCache(cacheName); - if (res != null) + if (res != null) { return res; - tlog("Terminology Server: $validate-code "+describeValidationParameters(pin)); - for (ParametersParameterComponent pp : pin.getParameter()) - if (pp.getName().equals("profile")) + } + tlog("Terminology Server: $validate-code " + describeValidationParameters(pin)); + for (ParametersParameterComponent pp : pin.getParameter()) { + if (pp.getName().equals("profile")) { throw new Error("Can only specify profile in the context"); - if (expProfile == null) + } + } + if (expProfile == null) { throw new Exception("No ExpansionProfile provided"); + } pin.addParameter().setName("profile").setResource(expProfile); Parameters pout = txServer.operateType(ValueSet.class, "validate-code", pin); @@ -565,29 +639,31 @@ public abstract class BaseWorkerContext implements IWorkerContext { String display = null; TerminologyServiceErrorClass err = TerminologyServiceErrorClass.UNKNOWN; for (ParametersParameterComponent p : pout.getParameter()) { - if (p.getName().equals("result")) + if (p.getName().equals("result")) { ok = ((BooleanType) p.getValue()).getValue().booleanValue(); - else if (p.getName().equals("message")) + } else if (p.getName().equals("message")) { message = ((StringType) p.getValue()).getValue(); - else if (p.getName().equals("display")) + } else if (p.getName().equals("display")) { display = ((StringType) p.getValue()).getValue(); - else if (p.getName().equals("cause")) { + } else if (p.getName().equals("cause")) { try { IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue()); - if (it == IssueType.UNKNOWN) + if (it == IssueType.UNKNOWN) { err = TerminologyServiceErrorClass.UNKNOWN; - else if (it == IssueType.NOTSUPPORTED) + } else if (it == IssueType.NOTSUPPORTED) { err = TerminologyServiceErrorClass.VALUESET_UNSUPPORTED; + } } catch (FHIRException e) { } } } - if (!ok) + if (!ok) { res = new ValidationResult(IssueSeverity.ERROR, message, err); - else if (display != null) + } else if (display != null) { res = new ValidationResult(new ConceptDefinitionComponent().setDisplay(display)); - else + } else { res = new ValidationResult(new ConceptDefinitionComponent()); + } saveToCache(res, cacheName); return res; } @@ -602,158 +678,191 @@ public abstract class BaseWorkerContext implements IWorkerContext { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); for (ParametersParameterComponent p : pin.getParameter()) { if (p.hasValue() && p.getValue() instanceof PrimitiveType) { - b.append(p.getName()+"="+((PrimitiveType) p.getValue()).asStringValue()); + b.append(p.getName() + "=" + ((PrimitiveType) p.getValue()).asStringValue()); } else if (p.hasValue() && p.getValue() instanceof Coding) { - b.append("system="+((Coding) p.getValue()).getSystem()); - b.append("code="+((Coding) p.getValue()).getCode()); - b.append("display="+((Coding) p.getValue()).getDisplay()); + b.append("system=" + ((Coding) p.getValue()).getSystem()); + b.append("code=" + ((Coding) p.getValue()).getCode()); + b.append("display=" + ((Coding) p.getValue()).getDisplay()); } else if (p.hasValue() && p.getValue() instanceof CodeableConcept) { if (((CodeableConcept) p.getValue()).hasCoding()) { Coding c = ((CodeableConcept) p.getValue()).getCodingFirstRep(); - b.append("system="+c.getSystem()); - b.append("code="+c.getCode()); - b.append("display="+c.getDisplay()); + b.append("system=" + c.getSystem()); + b.append("code=" + c.getCode()); + b.append("display=" + c.getDisplay()); } else if (((CodeableConcept) p.getValue()).hasText()) { - b.append("text="+((CodeableConcept) p.getValue()).getText()); + b.append("text=" + ((CodeableConcept) p.getValue()).getText()); } } else if (p.hasResource() && (p.getResource() instanceof ValueSet)) { - b.append("valueset="+getVSSummary((ValueSet) p.getResource())); - } + b.append("valueset=" + getVSSummary((ValueSet) p.getResource())); + } } return b.toString(); } private ValidationResult loadFromCache(String fn) throws FileNotFoundException, IOException { - if (fn == null) + if (fn == null) { return null; - if (!(new File(fn).exists())) + } + if (!(new File(fn).exists())) { return null; + } String cnt = TextFile.fileToString(fn); - if (cnt.startsWith("!error: ")) + if (cnt.startsWith("!error: ")) { return new ValidationResult(IssueSeverity.ERROR, cnt.substring(8)); - else if (cnt.startsWith("!warning: ")) + } else if (cnt.startsWith("!warning: ")) { return new ValidationResult(IssueSeverity.ERROR, cnt.substring(10)); - else + } else { return new ValidationResult(new ConceptDefinitionComponent().setDisplay(cnt)); + } } private void saveToCache(ValidationResult res, String cacheName) throws IOException { - if (cacheName == null) + if (cacheName == null) { return; - if (res.getDisplay() != null) + } + if (res.getDisplay() != null) { TextFile.stringToFile(res.getDisplay(), cacheName); - else if (res.getMessage() != null) { - if (res.getSeverity() == IssueSeverity.WARNING) - TextFile.stringToFile("!warning: "+res.getMessage(), cacheName); - else - TextFile.stringToFile("!error: "+res.getMessage(), cacheName); + } else if (res.getMessage() != null) { + if (res.getSeverity() == IssueSeverity.WARNING) { + TextFile.stringToFile("!warning: " + res.getMessage(), cacheName); + } else { + TextFile.stringToFile("!error: " + res.getMessage(), cacheName); + } } } private String generateCacheName(Parameters pin) throws IOException { - if (cache == null) + if (cache == null) { return null; + } String json = new JsonParser().composeString(pin); - return Utilities.path(cache, "vc"+Integer.toString(json.hashCode())+".json"); + return Utilities.path(cache, "vc" + Integer.toString(json.hashCode()) + ".json"); } @Override - public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heirachical) throws TerminologyServiceException { + public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heirachical) + throws TerminologyServiceException { ValueSet vs = new ValueSet(); vs.setCompose(new ValueSetComposeComponent()); vs.getCompose().getInclude().add(inc); ValueSetExpansionOutcome vse = expandVS(vs, true, heirachical); ValueSet valueset = vse.getValueset(); - if (valueset == null) - throw new TerminologyServiceException("Error Expanding ValueSet: "+vse.getError()); + if (valueset == null) { + throw new TerminologyServiceException("Error Expanding ValueSet: " + vse.getError()); + } return valueset.getExpansion(); } @Override public ValidationResult validateCode(String system, String code, String display) { try { - if (codeSystems.containsKey(system) && codeSystems.get(system) != null) + if (codeSystems.containsKey(system) && codeSystems.get(system) != null) { return verifyCodeInCodeSystem(codeSystems.get(system), system, code, display); - else - return verifyCodeExternal(null, new Coding().setSystem(system).setCode(code).setDisplay(display), false); + } else { + return verifyCodeExternal(null, + new Coding().setSystem(system).setCode(code).setDisplay(display), false); + } } catch (Exception e) { - return new ValidationResult(IssueSeverity.FATAL, "Error validating code \""+code+"\" in system \""+system+"\": "+e.getMessage()); + return new ValidationResult(IssueSeverity.FATAL, + "Error validating code \"" + code + "\" in system \"" + system + "\": " + e.getMessage()); } } @Override public ValidationResult validateCode(Coding code, ValueSet vs) { - if (codeSystems.containsKey(code.getSystem()) && codeSystems.get(code.getSystem()) != null) + if (codeSystems.containsKey(code.getSystem()) && codeSystems.get(code.getSystem()) != null) { try { - return verifyCodeInCodeSystem(codeSystems.get(code.getSystem()), code.getSystem(), code.getCode(), code.getDisplay()); + return verifyCodeInCodeSystem(codeSystems.get(code.getSystem()), code.getSystem(), + code.getCode(), code.getDisplay()); } catch (Exception e) { - return new ValidationResult(IssueSeverity.FATAL, "Error validating code \""+code+"\" in system \""+code.getSystem()+"\": "+e.getMessage()); + return new ValidationResult(IssueSeverity.FATAL, + "Error validating code \"" + code + "\" in system \"" + code.getSystem() + "\": " + e + .getMessage()); } - else if (vs.hasExpansion()) + } else if (vs.hasExpansion()) { try { return verifyCodeInternal(vs, code.getSystem(), code.getCode(), code.getDisplay()); } catch (Exception e) { - return new ValidationResult(IssueSeverity.FATAL, "Error validating code \""+code+"\" in system \""+code.getSystem()+"\": "+e.getMessage()); + return new ValidationResult(IssueSeverity.FATAL, + "Error validating code \"" + code + "\" in system \"" + code.getSystem() + "\": " + e + .getMessage()); } - else + } else { try { return verifyCodeExternal(vs, code, true); } catch (Exception e) { - return new ValidationResult(IssueSeverity.WARNING, "Error validating code \""+code+"\" in system \""+code.getSystem()+"\": "+e.getMessage()); + return new ValidationResult(IssueSeverity.WARNING, + "Error validating code \"" + code + "\" in system \"" + code.getSystem() + "\": " + e + .getMessage()); } + } } @Override public ValidationResult validateCode(CodeableConcept code, ValueSet vs) { try { - if (vs.hasExpansion()) + if (vs.hasExpansion()) { return verifyCodeInternal(vs, code); - else { + } else { // we'll try expanding first; if that doesn't work, then we'll just pass it to the server to validate // ... could be a problem if the server doesn't have the code systems we have locally, so we try not to depend on the server try { ValueSetExpansionOutcome vse = expandVS(vs, true, false); - if (vse.getValueset() != null && !hasTooCostlyExpansion(vse.getValueset())) + if (vse.getValueset() != null && !hasTooCostlyExpansion(vse.getValueset())) { return verifyCodeInternal(vse.getValueset(), code); + } } catch (Exception e) { // failed? we'll just try the server - } + } return verifyCodeExternal(vs, code, true); } } catch (Exception e) { - return new ValidationResult(IssueSeverity.FATAL, "Error validating code \""+code.toString()+"\": "+e.getMessage(), TerminologyServiceErrorClass.SERVER_ERROR); + return new ValidationResult(IssueSeverity.FATAL, + "Error validating code \"" + code.toString() + "\": " + e.getMessage(), + TerminologyServiceErrorClass.SERVER_ERROR); } } private boolean hasTooCostlyExpansion(ValueSet valueset) { - return valueset != null && valueset.hasExpansion() && ToolingExtensions.hasExtension(valueset.getExpansion(), "http://hl7.org/fhir/StructureDefinition/valueset-toocostly"); + return valueset != null && valueset.hasExpansion() && ToolingExtensions + .hasExtension(valueset.getExpansion(), + "http://hl7.org/fhir/StructureDefinition/valueset-toocostly"); } @Override public ValidationResult validateCode(String system, String code, String display, ValueSet vs) { try { - if (system == null && display == null) + if (system == null && display == null) { return verifyCodeInternal(vs, code); - if ((codeSystems.containsKey(system) && codeSystems.get(system) != null) || vs.hasExpansion()) + } + if ((codeSystems.containsKey(system) && codeSystems.get(system) != null) || vs + .hasExpansion()) { return verifyCodeInternal(vs, system, code, display); - else - return verifyCodeExternal(vs, new Coding().setSystem(system).setCode(code).setDisplay(display), true); + } else { + return verifyCodeExternal(vs, + new Coding().setSystem(system).setCode(code).setDisplay(display), true); + } } catch (Exception e) { - return new ValidationResult(IssueSeverity.FATAL, "Error validating code \""+code+"\" in system \""+system+"\": "+e.getMessage(), TerminologyServiceErrorClass.SERVER_ERROR); + return new ValidationResult(IssueSeverity.FATAL, + "Error validating code \"" + code + "\" in system \"" + system + "\": " + e.getMessage(), + TerminologyServiceErrorClass.SERVER_ERROR); } } @Override - public ValidationResult validateCode(String system, String code, String display, ConceptSetComponent vsi) { + public ValidationResult validateCode(String system, String code, String display, + ConceptSetComponent vsi) { try { ValueSet vs = new ValueSet(); vs.setUrl(Utilities.makeUuidUrn()); vs.getCompose().addInclude(vsi); - return verifyCodeExternal(vs, new Coding().setSystem(system).setCode(code).setDisplay(display), true); + return verifyCodeExternal(vs, + new Coding().setSystem(system).setCode(code).setDisplay(display), true); } catch (Exception e) { - return new ValidationResult(IssueSeverity.FATAL, "Error validating code \""+code+"\" in system \""+system+"\": "+e.getMessage()); + return new ValidationResult(IssueSeverity.FATAL, + "Error validating code \"" + code + "\" in system \"" + system + "\": " + e.getMessage()); } } @@ -775,120 +884,158 @@ public abstract class BaseWorkerContext implements IWorkerContext { @Override public List findMapsForSource(String url) { List res = new ArrayList(); - for (ConceptMap map : maps.values()) - if (((Reference) map.getSource()).getReference().equals(url)) + for (ConceptMap map : maps.values()) { + if (((Reference) map.getSource()).getReference().equals(url)) { res.add(map); + } + } return res; } private ValidationResult verifyCodeInternal(ValueSet vs, CodeableConcept code) throws Exception { for (Coding c : code.getCoding()) { ValidationResult res = verifyCodeInternal(vs, c.getSystem(), c.getCode(), c.getDisplay()); - if (res.isOk()) + if (res.isOk()) { return res; + } } - if (code.getCoding().isEmpty()) + if (code.getCoding().isEmpty()) { return new ValidationResult(IssueSeverity.ERROR, "None code provided"); - else - return new ValidationResult(IssueSeverity.ERROR, "None of the codes are in the specified value set"); + } else { + return new ValidationResult(IssueSeverity.ERROR, + "None of the codes are in the specified value set"); + } } - private ValidationResult verifyCodeInternal(ValueSet vs, String system, String code, String display) throws Exception { - if (vs.hasExpansion()) + private ValidationResult verifyCodeInternal(ValueSet vs, String system, String code, + String display) throws Exception { + if (vs.hasExpansion()) { return verifyCodeInExpansion(vs, system, code, display); - else { + } else { ValueSetExpansionOutcome vse = expansionCache.getExpander().expand(vs, null); - if (vse.getValueset() != null) - return verifyCodeExternal(vs, new Coding().setSystem(system).setCode(code).setDisplay(display), false); - else + if (vse.getValueset() != null) { + return verifyCodeExternal(vs, + new Coding().setSystem(system).setCode(code).setDisplay(display), false); + } else { return verifyCodeInExpansion(vse.getValueset(), system, code, display); + } } } - private ValidationResult verifyCodeInternal(ValueSet vs, String code) throws FileNotFoundException, ETooCostly, IOException, FHIRException { - if (vs.hasExpansion()) + private ValidationResult verifyCodeInternal(ValueSet vs, String code) + throws FileNotFoundException, ETooCostly, IOException, FHIRException { + if (vs.hasExpansion()) { return verifyCodeInExpansion(vs, code); - else { + } else { ValueSetExpansionOutcome vse = expansionCache.getExpander().expand(vs, null); - if (vse.getValueset() == null) + if (vse.getValueset() == null) { return new ValidationResult(IssueSeverity.ERROR, vse.getError(), vse.getErrorClass()); - else + } else { return verifyCodeInExpansion(vse.getValueset(), code); + } } } - private ValidationResult verifyCodeInCodeSystem(CodeSystem cs, String system, String code, String display) throws Exception { + private ValidationResult verifyCodeInCodeSystem(CodeSystem cs, String system, String code, + String display) throws Exception { ConceptDefinitionComponent cc = findCodeInConcept(cs.getConcept(), code); - if (cc == null) - if (cs.getContent().equals(CodeSystem.CodeSystemContentMode.COMPLETE)) - return new ValidationResult(IssueSeverity.ERROR, "Unknown Code "+code+" in "+cs.getUrl()); - else if (!cs.getContent().equals(CodeSystem.CodeSystemContentMode.NOTPRESENT)) - return new ValidationResult(IssueSeverity.WARNING, "Unknown Code "+code+" in partial code list of "+cs.getUrl()); - else - return verifyCodeExternal(null, new Coding().setSystem(system).setCode(code).setDisplay(display), false); + if (cc == null) { + if (cs.getContent().equals(CodeSystem.CodeSystemContentMode.COMPLETE)) { + return new ValidationResult(IssueSeverity.ERROR, + "Unknown Code " + code + " in " + cs.getUrl()); + } else if (!cs.getContent().equals(CodeSystem.CodeSystemContentMode.NOTPRESENT)) { + return new ValidationResult(IssueSeverity.WARNING, + "Unknown Code " + code + " in partial code list of " + cs.getUrl()); + } else { + return verifyCodeExternal(null, + new Coding().setSystem(system).setCode(code).setDisplay(display), false); + } + } // // return new ValidationResult(IssueSeverity.WARNING, "A definition was found for "+cs.getUrl()+", but it has no codes in the definition"); // return new ValidationResult(IssueSeverity.ERROR, "Unknown Code "+code+" in "+cs.getUrl()); - if (display == null) + if (display == null) { return new ValidationResult(cc); + } CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); if (cc.hasDisplay()) { b.append(cc.getDisplay()); - if (display.equalsIgnoreCase(cc.getDisplay())) + if (display.equalsIgnoreCase(cc.getDisplay())) { return new ValidationResult(cc); + } } for (ConceptDefinitionDesignationComponent ds : cc.getDesignation()) { b.append(ds.getValue()); - if (display.equalsIgnoreCase(ds.getValue())) + if (display.equalsIgnoreCase(ds.getValue())) { return new ValidationResult(cc); + } } - return new ValidationResult(IssueSeverity.WARNING, "Display Name for "+code+" must be one of '"+b.toString()+"'", cc); + return new ValidationResult(IssueSeverity.WARNING, + "Display Name for " + code + " must be one of '" + b.toString() + "'", cc); } - private ValidationResult verifyCodeInExpansion(ValueSet vs, String system,String code, String display) { + private ValidationResult verifyCodeInExpansion(ValueSet vs, String system, String code, + String display) { ValueSetExpansionContainsComponent cc = findCode(vs.getExpansion().getContains(), code); - if (cc == null) - return new ValidationResult(IssueSeverity.ERROR, "Unknown Code "+code+" in "+vs.getUrl()); - if (display == null) - return new ValidationResult(new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); + if (cc == null) { + return new ValidationResult(IssueSeverity.ERROR, + "Unknown Code " + code + " in " + vs.getUrl()); + } + if (display == null) { + return new ValidationResult( + new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); + } if (cc.hasDisplay()) { - if (display.equalsIgnoreCase(cc.getDisplay())) - return new ValidationResult(new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); - return new ValidationResult(IssueSeverity.WARNING, "Display Name for "+code+" must be '"+cc.getDisplay()+"'", new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); + if (display.equalsIgnoreCase(cc.getDisplay())) { + return new ValidationResult( + new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); + } + return new ValidationResult(IssueSeverity.WARNING, + "Display Name for " + code + " must be '" + cc.getDisplay() + "'", + new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); } return null; } private ValidationResult verifyCodeInExpansion(ValueSet vs, String code) throws FHIRException { - if (vs.getExpansion().hasExtension("http://hl7.org/fhir/StructureDefinition/valueset-toocostly")) { - throw new FHIRException("Unable to validate core - value set is too costly to expand"); + if (vs.getExpansion() + .hasExtension("http://hl7.org/fhir/StructureDefinition/valueset-toocostly")) { + throw new FHIRException("Unable to validate core - value set is too costly to expand"); } else { ValueSetExpansionContainsComponent cc = findCode(vs.getExpansion().getContains(), code); - if (cc == null) - return new ValidationResult(IssueSeverity.ERROR, "Unknown Code "+code+" in "+vs.getUrl()); + if (cc == null) { + return new ValidationResult(IssueSeverity.ERROR, + "Unknown Code " + code + " in " + vs.getUrl()); + } return null; } } - private ValueSetExpansionContainsComponent findCode(List contains, String code) { + private ValueSetExpansionContainsComponent findCode( + List contains, String code) { for (ValueSetExpansionContainsComponent cc : contains) { - if (code.equals(cc.getCode())) + if (code.equals(cc.getCode())) { return cc; + } ValueSetExpansionContainsComponent c = findCode(cc.getContains(), code); - if (c != null) + if (c != null) { return c; + } } return null; } - private ConceptDefinitionComponent findCodeInConcept(List concept, String code) { + private ConceptDefinitionComponent findCodeInConcept(List concept, + String code) { for (ConceptDefinitionComponent cc : concept) { - if (code.equals(cc.getCode())) + if (code.equals(cc.getCode())) { return cc; + } ConceptDefinitionComponent c = findCodeInConcept(cc.getConcept(), code); - if (c != null) + if (c != null) { return c; + } } return null; } @@ -954,26 +1101,29 @@ public abstract class BaseWorkerContext implements IWorkerContext { } public void cacheResource(Resource r) throws Exception { - if (r instanceof ValueSet) + if (r instanceof ValueSet) { seeValueSet(((ValueSet) r).getUrl(), (ValueSet) r); - else if (r instanceof CodeSystem) + } else if (r instanceof CodeSystem) { seeCodeSystem(((CodeSystem) r).getUrl(), (CodeSystem) r); - else if (r instanceof StructureDefinition) { + } else if (r instanceof StructureDefinition) { StructureDefinition sd = (StructureDefinition) r; - if ("http://hl7.org/fhir/StructureDefinition/Extension".equals(sd.getBaseDefinition())) + if ("http://hl7.org/fhir/StructureDefinition/Extension".equals(sd.getBaseDefinition())) { seeExtensionDefinition(sd.getUrl(), sd); - else if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT) + } else if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT) { seeProfile(sd.getUrl(), sd); + } } } public void dropResource(String type, String id) throws FHIRException { - if (type.equals("ValueSet")) - dropValueSet(id); - if (type.equals("CodeSystem")) - dropCodeSystem(id); + if (type.equals("ValueSet")) { + dropValueSet(id); + } + if (type.equals("CodeSystem")) { + dropCodeSystem(id); + } if (type.equals("StructureDefinition")) { - dropProfile(id); + dropProfile(id); dropExtensionDefinition(id); } } @@ -988,8 +1138,41 @@ public abstract class BaseWorkerContext implements IWorkerContext { @Override public StructureDefinition fetchTypeDefinition(String typeName) { - return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+typeName); + return fetchResource(StructureDefinition.class, + "http://hl7.org/fhir/StructureDefinition/" + typeName); } + @Override + public Locale getLocale() { + if (Objects.nonNull(locale)) { + return locale; + } else { + return Locale.US; + } + } + + @Override + public void setLocale(Locale locale) { + this.locale = locale; + setValidationMessageLanguage(getLocale()); + } + + @Override + public String formatMessage(String theMessage, Object... theMessageArguments) { + String message = theMessage; + if (Objects.nonNull(i18Nmessages) && i18Nmessages.containsKey(theMessage)) { + if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) { + message = MessageFormat.format(i18Nmessages.getString(theMessage), theMessageArguments); + } else { + message = i18Nmessages.getString(theMessage); + } + } + return message; + } + + @Override + public void setValidationMessageLanguage(Locale locale) { + i18Nmessages = ResourceBundle.getBundle("Messages", locale); + } } diff --git a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/IWorkerContext.java b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/IWorkerContext.java index f51e69f89..bcfc0ef98 100644 --- a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/IWorkerContext.java +++ b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/IWorkerContext.java @@ -22,6 +22,7 @@ package org.hl7.fhir.dstu3.context; import java.util.List; +import java.util.Locale; import java.util.Set; import org.hl7.fhir.dstu3.formats.IParser; @@ -236,7 +237,15 @@ public interface IWorkerContext { * @throws FHIRException */ public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heiarchical) throws TerminologyServiceException; - + + Locale getLocale(); + + void setLocale(Locale locale); + + String formatMessage(String theMessage, Object... theMessageArguments); + + void setValidationMessageLanguage(Locale locale); + public class ValidationResult { private ConceptDefinitionComponent definition; private IssueSeverity severity; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/BaseWorkerContext.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/BaseWorkerContext.java index 75a4b365a..62d11f7cf 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/BaseWorkerContext.java @@ -21,6 +21,10 @@ package org.hl7.fhir.r4.context; */ import com.google.gson.JsonObject; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.Objects; +import java.util.ResourceBundle; import org.apache.commons.lang3.StringUtils; import org.fhir.ucum.UcumService; import org.hl7.fhir.exceptions.DefinitionException; @@ -99,7 +103,9 @@ public abstract class BaseWorkerContext implements IWorkerContext { protected TerminologyCache txCache; private boolean tlogging = true; - + private Locale locale; + private ResourceBundle i18Nmessages; + public BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException { super(); txCache = new TerminologyCache(lock, null); @@ -1174,5 +1180,37 @@ public abstract class BaseWorkerContext implements IWorkerContext { return null; } + @Override + public Locale getLocale() { + if (Objects.nonNull(locale)){ + return locale; + } else { + return Locale.US; + } + } + + @Override + public void setLocale(Locale locale) { + this.locale = locale; + setValidationMessageLanguage(getLocale()); + } + + @Override + public String formatMessage(String theMessage, Object... theMessageArguments) { + String message = theMessage; + if (Objects.nonNull(i18Nmessages) && i18Nmessages.containsKey(theMessage)) { + if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) { + message = MessageFormat.format(i18Nmessages.getString(theMessage), theMessageArguments); + } else { + message = i18Nmessages.getString(theMessage); + } + } + return message; + } + + @Override + public void setValidationMessageLanguage(Locale locale) { + i18Nmessages = ResourceBundle.getBundle("Messages", locale ); + } } diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/IWorkerContext.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/IWorkerContext.java index 765379522..b5ce51f24 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/IWorkerContext.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/IWorkerContext.java @@ -22,6 +22,7 @@ package org.hl7.fhir.r4.context; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -283,7 +284,15 @@ public interface IWorkerContext { * @throws FHIRException */ public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException; - + + Locale getLocale(); + + void setLocale(Locale locale); + + String formatMessage(String theMessage, Object... theMessageArguments); + + void setValidationMessageLanguage(Locale locale); + public class ValidationResult { private ConceptDefinitionComponent definition; private IssueSeverity severity; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 7813013a9..10f17881b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -9,9 +9,9 @@ package org.hl7.fhir.r5.conformance; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,13 +31,13 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.ResourceBundle; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities.BaseTypeSlice; import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider.BindingResolution; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; @@ -95,7 +95,7 @@ import org.hl7.fhir.r5.utils.TranslatingUtilities; import org.hl7.fhir.r5.utils.formats.CSVWriter; import org.hl7.fhir.r5.utils.formats.XLSXWriter; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.TerminologyServiceOptions; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.validation.ValidationOptions; @@ -266,6 +266,7 @@ public class ProfileUtilities extends TranslatingUtilities { private boolean newSlicingProcessing; private String defWebRoot; private boolean autoFixSliceNames; + private ResourceBundle i18nMessages; public ProfileUtilities(IWorkerContext context, List messages, ProfileKnowledgeProvider pkp) { super(); @@ -273,7 +274,7 @@ public class ProfileUtilities extends TranslatingUtilities { this.messages = messages; this.pkp = pkp; } - + private class UnusedTracker { private boolean used; } @@ -298,19 +299,20 @@ public class ProfileUtilities extends TranslatingUtilities { } public interface ProfileKnowledgeProvider { - public class BindingResolution { + class BindingResolution { public String display; public String url; } - public boolean isDatatype(String typeSimple); - public boolean isResource(String typeSimple); - public boolean hasLinkFor(String typeSimple); - public String getLinkFor(String corePath, String typeSimple); - public BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException; - public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException; - public String getLinkForProfile(StructureDefinition profile, String url); - public boolean prependLinks(); - public String getLinkForUrl(String corePath, String s); + boolean isDatatype(String typeSimple); + boolean isResource(String typeSimple); + boolean hasLinkFor(String typeSimple); + String getLinkFor(String corePath, String typeSimple); + BindingResolution resolveBinding(StructureDefinition def, + ElementDefinitionBindingComponent binding, String path) throws FHIRException; + BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException; + String getLinkForProfile(StructureDefinition profile, String url); + boolean prependLinks(); + String getLinkForUrl(String corePath, String s); } @@ -321,7 +323,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (element.getContentReference().equals("#"+e.getId())) return getChildMap(profile, e); } - throw new DefinitionException("Unable to resolve name reference "+element.getContentReference()+" at path "+element.getPath()); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_NAME_REFERENCE__AT_PATH_, element.getContentReference(), element.getPath())); } else { List res = new ArrayList(); @@ -343,7 +345,7 @@ public class ProfileUtilities extends TranslatingUtilities { public List getSliceList(StructureDefinition profile, ElementDefinition element) throws DefinitionException { if (!element.hasSlicing()) - throw new Error("getSliceList should only be called when the element has slicing"); + throw new Error(context.formatMessage(I18nConstants.GETSLICELIST_SHOULD_ONLY_BE_CALLED_WHEN_THE_ELEMENT_HAS_SLICING)); List res = new ArrayList(); List elements = profile.getSnapshot().getElement(); @@ -382,9 +384,9 @@ public class ProfileUtilities extends TranslatingUtilities { List list = diff ? profile.getDifferential().getElement() : profile.getSnapshot().getElement(); for (ElementDefinition e : list) { if (e == null) - throw new Error("element = null: "+profile.getUrl()); + throw new Error(context.formatMessage(I18nConstants.ELEMENT__NULL_, profile.getUrl())); if (e.getId() == null) - throw new Error("element id = null: "+e.toString()+" on "+profile.getUrl()); + throw new Error(context.formatMessage(I18nConstants.ELEMENT_ID__NULL__ON_, e.toString(), profile.getUrl())); if (!capturing && id!=null && e.getId().equals(id)) { capturing = true; @@ -425,9 +427,9 @@ public class ProfileUtilities extends TranslatingUtilities { public void updateMaps(StructureDefinition base, StructureDefinition derived) throws DefinitionException { if (base == null) - throw new DefinitionException("no base profile provided"); + throw new DefinitionException(context.formatMessage(I18nConstants.NO_BASE_PROFILE_PROVIDED)); if (derived == null) - throw new DefinitionException("no derived structure provided"); + throw new DefinitionException(context.formatMessage(I18nConstants.NO_DERIVED_STRUCTURE_PROVIDED)); for (StructureDefinitionMappingComponent baseMap : base.getMapping()) { boolean found = false; @@ -458,30 +460,30 @@ public class ProfileUtilities extends TranslatingUtilities { */ public void generateSnapshot(StructureDefinition base, StructureDefinition derived, String url, String webUrl, String profileName) throws DefinitionException, FHIRException { if (base == null) { - throw new DefinitionException("no base profile provided"); + throw new DefinitionException(context.formatMessage(I18nConstants.NO_BASE_PROFILE_PROVIDED)); } if (derived == null) { - throw new DefinitionException("no derived structure provided"); + throw new DefinitionException(context.formatMessage(I18nConstants.NO_DERIVED_STRUCTURE_PROVIDED)); } checkNotGenerating(base, "Base for generating a snapshot for the profile "+derived.getUrl()); checkNotGenerating(derived, "Focus for generating a snapshot"); derived.setUserData("profileutils.snapshot.generating", true); if (!base.hasType()) { - throw new DefinitionException("Base profile "+base.getUrl()+" has no type"); + throw new DefinitionException(context.formatMessage(I18nConstants.BASE_PROFILE__HAS_NO_TYPE, base.getUrl())); } if (!derived.hasType()) { - throw new DefinitionException("Derived profile "+derived.getUrl()+" has no type"); + throw new DefinitionException(context.formatMessage(I18nConstants.DERIVED_PROFILE__HAS_NO_TYPE, derived.getUrl())); } if (!derived.hasDerivation()) { - throw new DefinitionException("Derived profile "+derived.getUrl()+" has no derivation value and so can't be processed"); + throw new DefinitionException(context.formatMessage(I18nConstants.DERIVED_PROFILE__HAS_NO_DERIVATION_VALUE_AND_SO_CANT_BE_PROCESSED, derived.getUrl())); } if (!base.getType().equals(derived.getType()) && derived.getDerivation() == TypeDerivationRule.CONSTRAINT) { - throw new DefinitionException("Base & Derived profiles have different types ("+base.getUrl()+" = "+base.getType()+" vs "+derived.getUrl()+" = "+derived.getType()+")"); + throw new DefinitionException(context.formatMessage(I18nConstants.BASE__DERIVED_PROFILES_HAVE_DIFFERENT_TYPES____VS___, base.getUrl(), base.getType(), derived.getUrl(), derived.getType())); } if (snapshotStack.contains(derived.getUrl())) { - throw new DefinitionException("Circular snapshot references detected; cannot generate snapshot (stack = "+snapshotStack.toString()+")"); + throw new DefinitionException(context.formatMessage(I18nConstants.CIRCULAR_SNAPSHOT_REFERENCES_DETECTED_CANNOT_GENERATE_SNAPSHOT_STACK__, snapshotStack.toString())); } snapshotStack.add(derived.getUrl()); @@ -505,7 +507,7 @@ public class ProfileUtilities extends TranslatingUtilities { int diffCursor = 0; // we need a diff cursor because we can only look ahead, in the bound scoped by longer paths if (derived.hasDifferential() && !derived.getDifferential().getElementFirstRep().getPath().contains(".") && !derived.getDifferential().getElementFirstRep().getType().isEmpty()) - throw new Error("type on first differential element!"); + throw new Error(context.formatMessage(I18nConstants.TYPE_ON_FIRST_DIFFERENTIAL_ELEMENT)); for (ElementDefinition e : derived.getDifferential().getElement()) e.clearUserData(GENERATED_IN_SNAPSHOT); @@ -536,7 +538,7 @@ public class ProfileUtilities extends TranslatingUtilities { } if (!derived.getSnapshot().getElementFirstRep().getType().isEmpty()) - throw new Error("type on first snapshot element for "+derived.getSnapshot().getElementFirstRep().getPath()+" in "+derived.getUrl()+" from "+base.getUrl()); + throw new Error(context.formatMessage(I18nConstants.TYPE_ON_FIRST_SNAPSHOT_ELEMENT_FOR__IN__FROM_, derived.getSnapshot().getElementFirstRep().getPath(), derived.getUrl(), base.getUrl())); updateMaps(base, derived); if (debug) { @@ -553,7 +555,7 @@ public class ProfileUtilities extends TranslatingUtilities { int ce = 0; for (ElementDefinition e : diff.getElement()) { if (!e.hasUserData("diff-source")) - throw new Error("Unxpected internal condition - no source on diff element"); + throw new Error(context.formatMessage(I18nConstants.UNXPECTED_INTERNAL_CONDITION__NO_SOURCE_ON_DIFF_ELEMENT)); else { if (e.hasUserData(DERIVATION_EQUALS)) ((Base) e.getUserData("diff-source")).setUserData(DERIVATION_EQUALS, e.getUserData(DERIVATION_EQUALS)); @@ -599,7 +601,7 @@ public class ProfileUtilities extends TranslatingUtilities { } } } - // last, check for wrong profiles or target profiles + // last, check for wrong profiles or target profiles for (ElementDefinition ed : derived.getSnapshot().getElement()) { for (TypeRefComponent t : ed.getType()) { for (UriType u : t.getProfile()) { @@ -639,14 +641,14 @@ public class ProfileUtilities extends TranslatingUtilities { boolean first = true; for (ElementDefinition ed : elements) { if (!ed.hasPath()) { - throw new FHIRException("No path on element in differential in "+url); + throw new FHIRException(context.formatMessage(I18nConstants.NO_PATH_ON_ELEMENT_IN_DIFFERENTIAL_IN_, url)); } String p = ed.getPath(); if (p == null) { - throw new FHIRException("No path value on element in differential in "+url); + throw new FHIRException(context.formatMessage(I18nConstants.NO_PATH_VALUE_ON_ELEMENT_IN_DIFFERENTIAL_IN_, url)); } if (!((first && type.equals(p)) || p.startsWith(type+"."))) { - throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": must start with "+type+"."+(first ? " (o be '"+type+"')" : "")); + throw new FHIRException(context.formatMessage(I18nConstants.ILLEGAL_PATH__IN_DIFFERENTIAL_IN__MUST_START_WITH_, p, url, type, (first ? " (o be '"+type+"')" : ""))); } if (p.contains(".")) { // Element names (the parts of a path delineated by the '.' character) SHALL NOT contain whitespace (i.e. Unicode characters marked as whitespace) @@ -656,25 +658,25 @@ public class ProfileUtilities extends TranslatingUtilities { String[] pl = p.split("\\."); for (String pp : pl) { if (pp.length() < 1) { - throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": name portion mising ('..')"); + throw new FHIRException(context.formatMessage(I18nConstants.ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NAME_PORTION_MISING_, p, url)); } if (pp.length() > 64) { - throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": name portion exceeds 64 chars in length"); + throw new FHIRException(context.formatMessage(I18nConstants.ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NAME_PORTION_EXCEEDS_64_CHARS_IN_LENGTH, p, url)); } for (char ch : pp.toCharArray()) { if (Character.isWhitespace(ch)) { - throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": no unicode whitespace"); + throw new FHIRException(context.formatMessage(I18nConstants.ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NO_UNICODE_WHITESPACE, p, url)); } if (Utilities.existsInList(ch, ',', ':', ';', '\'', '"', '/', '|', '?', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '{', '}')) { - throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": illegal character '"+ch+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ILLEGAL_PATH__IN_DIFFERENTIAL_IN__ILLEGAL_CHARACTER_, p, url, ch)); } if (ch < ' ' || ch > 'z') { - throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": illegal character '"+ch+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ILLEGAL_PATH__IN_DIFFERENTIAL_IN__ILLEGAL_CHARACTER_, p, url, ch)); } } if (pp.contains("[") || pp.contains("]")) { if (!pp.endsWith("[x]") || (pp.substring(0, pp.length()-3).contains("[") || (pp.substring(0, pp.length()-3).contains("]")))) { - throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": illegal characters []"); + throw new FHIRException(context.formatMessage(I18nConstants.ILLEGAL_PATH__IN_DIFFERENTIAL_IN__ILLEGAL_CHARACTERS_, p, url)); } } } @@ -828,7 +830,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (resultPathBase == null) resultPathBase = outcome.getPath(); else if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path - outcome.getPath() = "+outcome.getPath()+", resultPathBase = "+resultPathBase); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__, outcome.getPath(), resultPathBase)); result.getElement().add(outcome); if (hasInnerDiffMatches(differential, cpath, diffCursor, diffLimit, base.getElement(), true)) { // well, the profile walks into this, so we need to as well @@ -838,17 +840,17 @@ public class ProfileUtilities extends TranslatingUtilities { baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor+1, baseLimit); } else { if (outcome.getType().size() == 0) { - throw new DefinitionException(diffMatches.get(0).getPath()+" has no children ("+differential.getElement().get(diffCursor).getPath()+") and no types in profile "+profileName); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), profileName)); } if (outcome.getType().size() > 1) { for (TypeRefComponent t : outcome.getType()) { if (!t.getWorkingCode().equals("Reference")) - throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); } } StructureDefinition dt = getProfileForDataType(outcome.getType().get(0)); if (dt == null) - throw new DefinitionException("Unknown type "+outcome.getType().get(0)+" at "+diffMatches.get(0).getPath()); + throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath())); contextName = dt.getUrl(); int start = diffCursor; while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+".")) @@ -868,7 +870,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!sd.hasSnapshot()) { StructureDefinition sdb = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); if (sdb == null) - throw new DefinitionException("Unable to find base "+sd.getBaseDefinition()+" for "+sd.getUrl()); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), sd.getUrl())); checkNotGenerating(sdb, "an extension base"); generateSnapshot(sdb, sd, sd.getUrl(), (sdb.hasUserData("path")) ? Utilities.extractBaseUrl(sdb.getUserString("path")) : webUrl, sd.getName()); } @@ -881,7 +883,7 @@ public class ProfileUtilities extends TranslatingUtilities { src = t; } if (src == null) - throw new DefinitionException("Unable to find element "+eid+" in "+p.getValue()); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT__IN_, eid, p.getValue())); } else src = sd.getSnapshot().getElement().get(0); template = src.copy().setPath(currentBase.getPath()); @@ -914,7 +916,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (resultPathBase == null) resultPathBase = outcome.getPath(); else if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path"); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); baseCursor++; diffCursor = differential.getElement().indexOf(diffMatches.get(0))+1; @@ -941,7 +943,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension")) nonExtension = true; if (nonExtension) - throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); } } } @@ -951,7 +953,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (outcome.hasContentReference()) { ElementDefinition tgt = getElementById(base.getElement(), outcome.getContentReference()); if (tgt == null) - throw new DefinitionException("Unable to resolve reference to "+outcome.getContentReference()); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference())); replaceFromContentReference(outcome, tgt); int nbc = base.getElement().indexOf(tgt)+1; int nbl = nbc; @@ -961,7 +963,7 @@ public class ProfileUtilities extends TranslatingUtilities { } else { StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element"); if (dt == null) - throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") for type "+typeCode(outcome.getType())+" in profile "+profileName+", but can't find type"); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); contextName = dt.getUrl(); processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1, diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, new ArrayList(), srcSD); @@ -974,9 +976,9 @@ public class ProfileUtilities extends TranslatingUtilities { int ndc = differential.getElement().indexOf(diffMatches.get(0)); ElementDefinition elementToRemove = null; boolean shortCut = !typeList.isEmpty() && typeList.get(0).type != null; - // we come here whether they are sliced in the diff, or whether the short cut is used. + // we come here whether they are sliced in the diff, or whether the short cut is used. if (shortCut) { - // this is the short cut method, we've just dived in and specified a type slice. + // this is the short cut method, we've just dived in and specified a type slice. // in R3 (and unpatched R4, as a workaround right now... if (!FHIRVersion.isR4Plus(context.getVersion()) || !newSlicingProcessing) { // newSlicingProcessing is a work around for editorial loop dependency // we insert a cloned element with the right types at the start of the diffMatches @@ -992,9 +994,9 @@ public class ProfileUtilities extends TranslatingUtilities { differential.getElement().add(ndc, ed); elementToRemove = ed; } else { - // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. - // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. - // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element + // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. + // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. + // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element ElementDefinition ed = new ElementDefinition(); ed.setPath(determineTypeSlicePath(diffMatches.get(0).getPath(), cpath)); ed.setSlicing(new ElementDefinitionSlicingComponent()); @@ -1011,18 +1013,18 @@ public class ProfileUtilities extends TranslatingUtilities { if (diffMatches.get(0).getSlicing().hasOrdered()) { if (diffMatches.get(0).getSlicing().getOrdered()) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.ordered = true"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, cpath, url)); } } if (diffMatches.get(0).getSlicing().hasDiscriminator()) { if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.discriminator.count() > 1"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, cpath, url)); } if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != DiscriminatorType.TYPE) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.discriminator.type != 'type'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, cpath, url)); } if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.discriminator.path != '$this'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, cpath, url)); } } // check the slice names too while we're at it... @@ -1035,28 +1037,28 @@ public class ProfileUtilities extends TranslatingUtilities { if (autoFixSliceNames) { ts.defn.setSliceName(tn); } else { - throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice name must be '"+tn+"' but is '"+ts.defn.getSliceName()+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName())); } } if (!ts.defn.hasType()) { ts.defn.addType().setCode(ts.type); } else if (ts.defn.getType().size() > 1) { - throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice for type '"+tn+"' has more than one type '"+ts.defn.typeSummary()+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { - throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice for type '"+tn+"' has wrong type '"+ts.defn.typeSummary()+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); } } } - // ok passed the checks. + // ok passed the checks. // copy the root diff, and then process any children it has ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null, redirector, srcSD); if (e==null) - throw new FHIRException("Did not find type root: " + diffMatches.get(0).getPath()); + throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); // now set up slicing on the e (cause it was wiped by what we called. e.setSlicing(new ElementDefinitionSlicingComponent()); e.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this"); - e.getSlicing().setRules(SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention + e.getSlicing().setRules(SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention e.getSlicing().setOrdered(false); start++; @@ -1067,7 +1069,7 @@ public class ProfileUtilities extends TranslatingUtilities { // our processing scope for the differential is the item in the list, and all the items before the next one in the list if (diffMatches.get(i).getMin() > 0) { if (diffMatches.size() > i+1) { - throw new FHIRException("Invalid slicing : there is more than one type slice at "+diffMatches.get(i).getPath()+", but one of them ("+diffMatches.get(i).getSliceName()+") has min = 1, so the other slices cannot exist"); + throw new FHIRException(context.formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); } else { e.setMin(1); } @@ -1099,9 +1101,9 @@ public class ProfileUtilities extends TranslatingUtilities { if (!unbounded(currentBase) && !isSlicedToOneOnly(diffMatches.get(0))) // you can only slice an element that doesn't repeat if the sum total of your slices is limited to 1 // (but you might do that in order to split up constraints by type) - throw new DefinitionException("Attempt to a slice an element that does not repeat: "+currentBase.getPath()+"/"+currentBase.getPath()+" from "+contextName+" in "+url); + throw new DefinitionException(context.formatMessage(I18nConstants.ATTEMPT_TO_A_SLICE_AN_ELEMENT_THAT_DOES_NOT_REPEAT__FROM__IN_, currentBase.getPath(), currentBase.getPath(), contextName, url)); if (!diffMatches.get(0).hasSlicing() && !isExtension(currentBase)) // well, the diff has set up a slice, but hasn't defined it. this is an error - throw new DefinitionException("Differential does not have a slice: "+currentBase.getPath()+"/ (b:"+baseCursor+" of "+ baseLimit+" / "+ diffCursor +"/ "+diffLimit+") in profile "+url); + throw new DefinitionException(context.formatMessage(I18nConstants.DIFFERENTIAL_DOES_NOT_HAVE_A_SLICE__B_OF_____IN_PROFILE_, currentBase.getPath(), baseCursor, baseLimit, diffCursor, diffLimit, url)); // well, if it passed those preconditions then we slice the dest. int start = 0; @@ -1113,7 +1115,7 @@ public class ProfileUtilities extends TranslatingUtilities { ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null, redirector, srcSD); if (e==null) - throw new FHIRException("Did not find single slice: " + diffMatches.get(0).getPath()); + throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_SINGLE_SLICE_, diffMatches.get(0).getPath())); e.setSlicing(diffMatches.get(0).getSlicing()); start++; } else { @@ -1127,7 +1129,7 @@ public class ProfileUtilities extends TranslatingUtilities { else outcome.setSlicing(diffMatches.get(0).getSlicing().copy()); if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path"); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); // differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice. @@ -1135,7 +1137,7 @@ public class ProfileUtilities extends TranslatingUtilities { updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); removeStatusExtensions(outcome); if (!outcome.hasContentReference() && !outcome.hasType()) { - throw new DefinitionException("not done yet"); + throw new DefinitionException(context.formatMessage(I18nConstants.NOT_DONE_YET)); } start++; // result.getElement().remove(result.getElement().size()-1); @@ -1184,7 +1186,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (resultPathBase == null) resultPathBase = outcome.getPath(); else if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path"); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); // the profile walks into this, so we need to as well // did we implicitly step into a new type? @@ -1193,17 +1195,17 @@ public class ProfileUtilities extends TranslatingUtilities { baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor, baseLimit); } else { if (outcome.getType().size() == 0) { - throw new DefinitionException(diffMatches.get(0).getPath()+" has no children ("+differential.getElement().get(diffCursor).getPath()+") and no types in profile "+profileName); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), profileName)); } if (outcome.getType().size() > 1) { for (TypeRefComponent t : outcome.getType()) { if (!t.getWorkingCode().equals("Reference")) - throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); } } StructureDefinition dt = getProfileForDataType(outcome.getType().get(0)); if (dt == null) - throw new DefinitionException("Unknown type "+outcome.getType().get(0)+" at "+diffMatches.get(0).getPath()); + throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath())); contextName = dt.getUrl(); int start = diffCursor; while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+".")) @@ -1219,7 +1221,7 @@ public class ProfileUtilities extends TranslatingUtilities { ElementDefinition outcome = updateURLs(url, webUrl, base.getElement().get(baseCursor).copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path in profile " + profileName + ": "+outcome.getPath()+" vs " + resultPathBase); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, profileName, outcome.getPath(), resultPathBase)); result.getElement().add(outcome); // so we just copy it in baseCursor++; } @@ -1230,9 +1232,9 @@ public class ProfileUtilities extends TranslatingUtilities { int ndc = differential.getElement().indexOf(diffMatches.get(0)); ElementDefinition elementToRemove = null; boolean shortCut = (!typeList.isEmpty() && typeList.get(0).type != null) || (diffMatches.get(0).hasSliceName() && !diffMatches.get(0).hasSlicing()); - // we come here whether they are sliced in the diff, or whether the short cut is used. + // we come here whether they are sliced in the diff, or whether the short cut is used. if (shortCut) { - // this is the short cut method, we've just dived in and specified a type slice. + // this is the short cut method, we've just dived in and specified a type slice. // in R3 (and unpatched R4, as a workaround right now... if (!FHIRVersion.isR4Plus(context.getVersion()) || !newSlicingProcessing) { // newSlicingProcessing is a work around for editorial loop dependency // we insert a cloned element with the right types at the start of the diffMatches @@ -1248,9 +1250,9 @@ public class ProfileUtilities extends TranslatingUtilities { differential.getElement().add(ndc, ed); elementToRemove = ed; } else { - // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. - // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. - // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element + // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. + // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. + // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element ElementDefinition ed = new ElementDefinition(); ed.setPath(determineTypeSlicePath(diffMatches.get(0).getPath(), cpath)); ed.setSlicing(new ElementDefinitionSlicingComponent()); @@ -1267,18 +1269,18 @@ public class ProfileUtilities extends TranslatingUtilities { if (diffMatches.get(0).getSlicing().hasOrdered()) { if (diffMatches.get(0).getSlicing().getOrdered()) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.ordered = true"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, cpath, url)); } } if (diffMatches.get(0).getSlicing().hasDiscriminator()) { if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.discriminator.count() > 1"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, cpath, url)); } if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != DiscriminatorType.TYPE) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.discriminator.type != 'type'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, cpath, url)); } if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) { - throw new FHIRException("Error at path "+cpath+" in "+url+": Type slicing with slicing.discriminator.path != '$this'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, cpath, url)); } } // check the slice names too while we're at it... @@ -1288,27 +1290,27 @@ public class ProfileUtilities extends TranslatingUtilities { if (!ts.defn.hasSliceName()) { ts.defn.setSliceName(tn); } else if (!ts.defn.getSliceName().equals(tn)) { - throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice name must be '"+tn+"' but is '"+ts.defn.getSliceName()+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName())); } if (!ts.defn.hasType()) { ts.defn.addType().setCode(ts.type); } else if (ts.defn.getType().size() > 1) { - throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice for type '"+tn+"' has more than one type '"+ts.defn.typeSummary()+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { - throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice for type '"+tn+"' has wrong type '"+ts.defn.typeSummary()+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); } } } - // ok passed the checks. + // ok passed the checks. // copy the root diff, and then process any children it has ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, cpath, redirector, srcSD); if (e==null) - throw new FHIRException("Did not find type root: " + diffMatches.get(0).getPath()); + throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); // now set up slicing on the e (cause it was wiped by what we called. e.setSlicing(new ElementDefinitionSlicingComponent()); e.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this"); - e.getSlicing().setRules(SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention + e.getSlicing().setRules(SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention e.getSlicing().setOrdered(false); start++; @@ -1321,7 +1323,7 @@ public class ProfileUtilities extends TranslatingUtilities { // our processing scope for the differential is the item in the list, and all the items before the next one in the list if (diffMatches.get(i).getMin() > 0) { if (diffMatches.size() > i+1) { - throw new FHIRException("Invalid slicing : there is more than one type slice at "+diffMatches.get(i).getPath()+", but one of them ("+diffMatches.get(i).getSliceName()+") has min = 1, so the other slices cannot exist"); + throw new FHIRException(context.formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); } fixedType = type; } @@ -1373,11 +1375,11 @@ public class ProfileUtilities extends TranslatingUtilities { ElementDefinitionSlicingComponent dSlice = diffMatches.get(0).getSlicing(); ElementDefinitionSlicingComponent bSlice = currentBase.getSlicing(); if (dSlice.hasOrderedElement() && bSlice.hasOrderedElement() && !orderMatches(dSlice.getOrderedElement(), bSlice.getOrderedElement())) - throw new DefinitionException("Slicing rules on differential ("+summarizeSlicing(dSlice)+") do not match those on base ("+summarizeSlicing(bSlice)+") - order @ "+path+" ("+contextName+")"); + throw new DefinitionException(context.formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___ORDER___, summarizeSlicing(dSlice), summarizeSlicing(bSlice), path, contextName)); if (!discriminatorMatches(dSlice.getDiscriminator(), bSlice.getDiscriminator())) - throw new DefinitionException("Slicing rules on differential ("+summarizeSlicing(dSlice)+") do not match those on base ("+summarizeSlicing(bSlice)+") - disciminator @ "+path+" ("+contextName+")"); + throw new DefinitionException(context.formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___DISCIMINATOR___, summarizeSlicing(dSlice), summarizeSlicing(bSlice), path, contextName)); if (!currentBase.isChoice() && !ruleMatches(dSlice.getRules(), bSlice.getRules())) - throw new DefinitionException("Slicing rules on differential ("+summarizeSlicing(dSlice)+") do not match those on base ("+summarizeSlicing(bSlice)+") - rule @ "+path+" ("+contextName+")"); + throw new DefinitionException(context.formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___, summarizeSlicing(dSlice), summarizeSlicing(bSlice), path, contextName)); } ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); @@ -1387,7 +1389,7 @@ public class ProfileUtilities extends TranslatingUtilities { updateFromDefinition(outcome, diffMatches.get(0), profileName, closed, url, srcSD); // if there's no slice, we don't want to update the unsliced description removeStatusExtensions(outcome); } else if (!diffMatches.get(0).hasSliceName()) - diffMatches.get(0).setUserData(GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called + diffMatches.get(0).setUserData(GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called result.getElement().add(outcome); @@ -1401,11 +1403,11 @@ public class ProfileUtilities extends TranslatingUtilities { int ndl = findEndOfElement(differential, ndx); if (nbl == baseCursor) { if (base.getElement().get(baseCursor).getType().size() != 1) { - throw new Error("Differential walks into '"+cpath+" (@ "+diffMatches.get(0).toString()+")', but the base does not, and there is not a single fixed type. The type is "+base.getElement().get(baseCursor).typeSummary()+". This is not handled yet"); + throw new Error(context.formatMessage(I18nConstants.DIFFERENTIAL_WALKS_INTO____BUT_THE_BASE_DOES_NOT_AND_THERE_IS_NOT_A_SINGLE_FIXED_TYPE_THE_TYPE_IS__THIS_IS_NOT_HANDLED_YET, cpath, diffMatches.get(0).toString(), base.getElement().get(baseCursor).typeSummary())); } StructureDefinition dt = getProfileForDataType(base.getElement().get(baseCursor).getType().get(0)); if (dt == null) { - throw new DefinitionException("Unknown type "+outcome.getType().get(0)+" at "+diffMatches.get(0).getPath()); + throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath())); } contextName = dt.getUrl(); while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+".")) @@ -1436,7 +1438,7 @@ public class ProfileUtilities extends TranslatingUtilities { outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setSlicing(null); if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path"); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); if (diffpos < diffMatches.size() && diffMatches.get(diffpos).hasSliceName() && diffMatches.get(diffpos).getSliceName().equals(outcome.getSliceName())) { // if there's a diff, we update the outcome with diff // no? updateFromDefinition(outcome, diffMatches.get(diffpos), profileName, closed, url); @@ -1458,7 +1460,7 @@ public class ProfileUtilities extends TranslatingUtilities { outcome = updateURLs(url, webUrl, base.getElement().get(baseCursor).copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path"); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); baseCursor++; } @@ -1469,11 +1471,11 @@ public class ProfileUtilities extends TranslatingUtilities { // finally, we process any remaining entries in diff, which are new (and which are only allowed if the base wasn't closed boolean checkImplicitTypes = false; if (closed && diffpos < diffMatches.size()) { - // this is a problem, unless we're on a polymorhpic type and we're going to constrain a slice that actually implicitly exists + // this is a problem, unless we're on a polymorhpic type and we're going to constrain a slice that actually implicitly exists if (currentBase.getPath().endsWith("[x]")) { checkImplicitTypes = true; } else { - throw new DefinitionException("The base snapshot marks a slicing as closed, but the differential tries to extend it in "+profileName+" at "+path+" ("+cpath+")"); + throw new DefinitionException(context.formatMessage(I18nConstants.THE_BASE_SNAPSHOT_MARKS_A_SLICING_AS_CLOSED_BUT_THE_DIFFERENTIAL_TRIES_TO_EXTEND_IT_IN__AT__, profileName, path, cpath)); } } if (diffpos == diffMatches.size()) { @@ -1484,14 +1486,14 @@ public class ProfileUtilities extends TranslatingUtilities { ElementDefinition diffItem = diffMatches.get(diffpos); for (ElementDefinition baseItem : baseMatches) if (baseItem.getSliceName().equals(diffItem.getSliceName())) - throw new DefinitionException("Named items are out of order in the slice"); + throw new DefinitionException(context.formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE)); outcome = updateURLs(url, webUrl, currentBase.copy()); // outcome = updateURLs(url, diffItem.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); updateFromBase(outcome, currentBase); outcome.setSlicing(null); if (!outcome.getPath().startsWith(resultPathBase)) - throw new DefinitionException("Adding wrong path"); + throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); updateFromDefinition(outcome, diffItem, profileName, trimDifferential, url, srcSD); removeStatusExtensions(outcome); @@ -1503,7 +1505,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (outcome.getType().size() > 1) for (TypeRefComponent t : outcome.getType()) { if (!t.getCode().equals("Reference")) - throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); } TypeRefComponent t = outcome.getType().get(0); if (t.getCode().equals("BackboneElement")) { @@ -1520,10 +1522,10 @@ public class ProfileUtilities extends TranslatingUtilities { } else { StructureDefinition dt = getProfileForDataType(outcome.getType().get(0)); // if (t.getCode().equals("Extension") && t.hasProfile() && !t.getProfile().contains(":")) { - // lloydfix dt = + // lloydfix dt = // } if (dt == null) - throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") for type "+typeCode(outcome.getType())+" in profile "+profileName+", but can't find type"); + throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); contextName = dt.getUrl(); int start = diffCursor; while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) @@ -1547,7 +1549,7 @@ public class ProfileUtilities extends TranslatingUtilities { for (ElementDefinition e : result.getElement()) { i++; if (e.hasMinElement() && e.getMinElement().getValue()==null) - throw new Error("null min"); + throw new Error(context.formatMessage(I18nConstants.NULL_MIN)); } return res; } @@ -1555,7 +1557,7 @@ public class ProfileUtilities extends TranslatingUtilities { private void checkNotGenerating(StructureDefinition sd, String role) { if (sd.hasUserData("profileutils.snapshot.generating")) { - throw new FHIRException("Attempt to use a snapshot on profile '"+sd.getUrl()+"' as "+role+" before it is generated"); + throw new FHIRException(context.formatMessage(I18nConstants.ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED, sd.getUrl(), role)); } } @@ -1580,12 +1582,12 @@ public class ProfileUtilities extends TranslatingUtilities { } else if (isPrimitive(Utilities.uncapitalize(t))) { fixedType = Utilities.uncapitalize(t); } else { - throw new FHIRException("Unexpected condition in differential: type-slice.type-list.size() == 10 and implicit slice name does not contain a valid type ('"+t+"'?) at "+diffMatches.get(i).getPath()+"/"+diffMatches.get(i).getSliceName()); + throw new FHIRException(context.formatMessage(I18nConstants.UNEXPECTED_CONDITION_IN_DIFFERENTIAL_TYPESLICETYPELISTSIZE__10_AND_IMPLICIT_SLICE_NAME_DOES_NOT_CONTAIN_A_VALID_TYPE__AT_, t, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); } } else if (diffMatches.get(i).getType().size() == 1) { fixedType = diffMatches.get(i).getType().get(0).getCode(); } else { - throw new FHIRException("Unexpected condition in differential: type-slice.type-list.size() != 1 at "+diffMatches.get(i).getPath()+"/"+diffMatches.get(i).getSliceName()); + throw new FHIRException(context.formatMessage(I18nConstants.UNEXPECTED_CONDITION_IN_DIFFERENTIAL_TYPESLICETYPELISTSIZE__1_AT_, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); } return fixedType; } @@ -2154,14 +2156,14 @@ public class ProfileUtilities extends TranslatingUtilities { for (int j = 0; j < p.length; j++) { ok = ok && sp.length > j && (p[j].equals(sp[j]) || isSameBase(p[j], sp[j])); } -// don't need this debug check - everything is ok -// if (ok != (statedPath.equals(path) || (path.endsWith("[x]") && statedPath.length() > path.length() - 2 && -// statedPath.substring(0, path.length()-3).equals(path.substring(0, path.length()-3)) && +// don't need this debug check - everything is ok +// if (ok != (statedPath.equals(path) || (path.endsWith("[x]") && statedPath.length() > path.length() - 2 && +// statedPath.substring(0, path.length()-3).equals(path.substring(0, path.length()-3)) && // (statedPath.length() < path.length() || !statedPath.substring(path.length()).contains("."))))) { // System.out.println("mismatch in paths: "+statedPath +" vs " +path); // } if (ok) { - /* + /* * Commenting this out because it raises warnings when profiling inherited elements. For example, * Error: unknown element 'Bundle.meta.profile' (or it is out of order) in profile ... (looking for 'Bundle.entry') * Not sure we have enough information here to do the check properly. Might be better done when we're sorting the profile? @@ -2317,7 +2319,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (derived.hasMinElement()) { if (!Base.compareDeep(derived.getMinElement(), base.getMinElement(), false)) { - if (derived.getMin() < base.getMin() && !derived.hasSliceName()) // in a slice, minimum cardinality rules do not apply + if (derived.getMin() < base.getMin() && !derived.hasSliceName()) // in a slice, minimum cardinality rules do not apply messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived min ("+Integer.toString(derived.getMin())+") cannot be less than base min ("+Integer.toString(base.getMin())+")", ValidationMessage.IssueSeverity.ERROR)); base.setMinElement(derived.getMinElement().copy()); } else if (trimDifferential) @@ -2460,7 +2462,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (derived.hasIsSummaryElement()) { if (!Base.compareDeep(derived.getIsSummaryElement(), base.getIsSummaryElement(), false)) { if (base.hasIsSummary()) - throw new Error("Error in profile "+pn+" at "+derived.getPath()+": Base isSummary = "+base.getIsSummaryElement().asStringValue()+", derived isSummary = "+derived.getIsSummaryElement().asStringValue()); + throw new Error(context.formatMessage(I18nConstants.ERROR_IN_PROFILE__AT__BASE_ISSUMMARY___DERIVED_ISSUMMARY__, pn, derived.getPath(), base.getIsSummaryElement().asStringValue(), derived.getIsSummaryElement().asStringValue())); base.setIsSummaryElement(derived.getIsSummaryElement().copy()); } else if (trimDifferential) derived.setIsSummaryElement(null); @@ -2587,7 +2589,7 @@ public class ProfileUtilities extends TranslatingUtilities { ok = true; } if (ok && ts.hasTargetProfile()) { - // check that any derived target has a reference chain back to one of the base target profiles + // check that any derived target has a reference chain back to one of the base target profiles for (UriType u : ts.getTargetProfile()) { String url = u.getValue(); boolean tgtOk = !td.hasTargetProfile() || td.hasTargetProfile(url); @@ -2606,7 +2608,7 @@ public class ProfileUtilities extends TranslatingUtilities { } if (!tgtOk) { if (messages == null) { - throw new FHIRException("Error at "+purl+"#"+derived.getPath()+": The target profile "+url+" is not valid constraint on the base ("+td.getTargetProfile()+")"); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_, purl, derived.getPath(), url, td.getTargetProfile())); } else { messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, derived.getPath(), "The target profile "+u.getValue()+" is not a valid constraint on the base ("+td.getTargetProfile()+") at "+derived.getPath(), IssueSeverity.ERROR)); } @@ -2615,7 +2617,7 @@ public class ProfileUtilities extends TranslatingUtilities { } } if (!ok) { - throw new DefinitionException("StructureDefinition "+purl+" at "+derived.getPath()+": illegal constrained type "+t+" from "+b.toString()+" in "+srcSD.getUrl()); + throw new DefinitionException(context.formatMessage(I18nConstants.STRUCTUREDEFINITION__AT__ILLEGAL_CONSTRAINED_TYPE__FROM__IN_, purl, derived.getPath(), t, b.toString(), srcSD.getUrl())); } } @@ -3194,7 +3196,7 @@ public class ProfileUtilities extends TranslatingUtilities { try { return gen.generate(model, imagePath, 0, outputTracker); } catch (org.hl7.fhir.exceptions.FHIRException e) { - throw new FHIRException("Error generating table for profile " + profile.getUrl() + ": " + e.getMessage(), e); + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_GENERATING_TABLE_FOR_PROFILE__, profile.getUrl(), e.getMessage()), e); } } @@ -3204,7 +3206,7 @@ public class ProfileUtilities extends TranslatingUtilities { while (i < list.size()) { String[] pathCurrent = list.get(i).getPath().split("\\."); String[] pathLast = list.get(i-1).getPath().split("\\."); - int firstDiff = 0; // the first entry must be a match + int firstDiff = 0; // the first entry must be a match while (firstDiff < pathCurrent.length && firstDiff < pathLast.length && pathCurrent[firstDiff].equals(pathLast[firstDiff])) { firstDiff++; } @@ -3754,7 +3756,7 @@ public class ProfileUtilities extends TranslatingUtilities { ref = p.startsWith("http:") || igmode ? p : Utilities.pathURL(corePath, p); } fixedUrl = getFixedUrl(ed); - if (fixedUrl != null) {// if its null, we guess that it's not a profiled extension? + if (fixedUrl != null) {// if its null, we guess that it's not a profiled extension? if (fixedUrl.equals(url)) fixedUrl = null; else { @@ -4021,7 +4023,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (ed.getPath().equals(path)) return ed; } - throw new FHIRException("Unable to find element "+path); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT_, path)); } @@ -4290,7 +4292,7 @@ public class ProfileUtilities extends TranslatingUtilities { return sd.getType(); if (Utilities.existsInList(value, "SimpleQuantity", "MoneyQuantity")) return "Quantity"; - throw new Error("Internal error - type not known "+value); + throw new Error(context.formatMessage(I18nConstants.INTERNAL_ERROR___TYPE_NOT_KNOWN_, value)); } @@ -4590,7 +4592,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (ed.getType().isEmpty() || isAbstract(ed.getType().get(0).getWorkingCode()) || ed.getType().get(0).getWorkingCode().equals(ed.getPath())) { if (ed.hasType() && "Resource".equals(ed.getType().get(0).getWorkingCode()) && child.getSelf().getType().get(0).hasProfile()) { if (child.getSelf().getType().get(0).getProfile().size() > 1) { - throw new FHIRException("Unhandled situation: resource is profiled to more than one option - cannot sort profile"); + throw new FHIRException(context.formatMessage(I18nConstants.UNHANDLED_SITUATION_RESOURCE_IS_PROFILED_TO_MORE_THAN_ONE_OPTION__CANNOT_SORT_PROFILE)); } StructureDefinition profile = context.fetchResource(StructureDefinition.class, child.getSelf().getType().get(0).getProfile().get(0).getValue()); while (profile != null && profile.getDerivation() == TypeDerivationRule.CONSTRAINT) { @@ -4613,12 +4615,12 @@ public class ProfileUtilities extends TranslatingUtilities { } else if (ed.getType().size() == 1 && !ed.getType().get(0).getWorkingCode().equals("*")) { StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getWorkingCode())); if (profile==null) - throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getWorkingCode()) + " in element " + ed.getPath()); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE__IN_ELEMENT_, sdNs(ed.getType().get(0).getWorkingCode()), ed.getPath())); ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name); } else if (child.getSelf().getType().size() == 1) { StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(child.getSelf().getType().get(0).getWorkingCode())); if (profile==null) - throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getWorkingCode()) + " in element " + ed.getPath()); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE__IN_ELEMENT_, sdNs(ed.getType().get(0).getWorkingCode()), ed.getPath())); ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), child.getSelf().getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name); } else if (ed.getPath().endsWith("[x]") && !child.getSelf().getPath().endsWith("[x]")) { String edLastNode = ed.getPath().replaceAll("(.*\\.)*(.*)", "$2"); @@ -4628,12 +4630,12 @@ public class ProfileUtilities extends TranslatingUtilities { p = Utilities.uncapitalize(p); StructureDefinition sd = context.fetchResource(StructureDefinition.class, sdNs(p)); if (sd == null) - throw new Error("Unable to find profile '"+p+"' at "+ed.getId()); + throw new Error(context.formatMessage(I18nConstants.UNABLE_TO_FIND_PROFILE__AT_, p, ed.getId())); ccmp = new ElementDefinitionComparer(false, sd.getSnapshot().getElement(), p, child.getSelf().getPath().length(), cmp.name); } else if (child.getSelf().hasType() && child.getSelf().getType().get(0).getWorkingCode().equals("Reference")) { for (TypeRefComponent t: child.getSelf().getType()) { if (!t.getWorkingCode().equals("Reference")) { - throw new Error("Can't have children on an element with a polymorphic type - you must slice and constrain the types first (sortElements: "+ed.getPath()+":"+typeCode(ed.getType())+")"); + throw new Error(context.formatMessage(I18nConstants.CANT_HAVE_CHILDREN_ON_AN_ELEMENT_WITH_A_POLYMORPHIC_TYPE__YOU_MUST_SLICE_AND_CONSTRAIN_THE_TYPES_FIRST_SORTELEMENTS_, ed.getPath(), typeCode(ed.getType()))); } } StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getWorkingCode())); @@ -4641,7 +4643,7 @@ public class ProfileUtilities extends TranslatingUtilities { } else if (!child.getSelf().hasType() && ed.getType().get(0).getWorkingCode().equals("Reference")) { for (TypeRefComponent t: ed.getType()) { if (!t.getWorkingCode().equals("Reference")) { - throw new Error("Not handled yet (sortElements: "+ed.getPath()+":"+typeCode(ed.getType())+")"); + throw new Error(context.formatMessage(I18nConstants.NOT_HANDLED_YET_SORTELEMENTS_, ed.getPath(), typeCode(ed.getType()))); } } StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getWorkingCode())); @@ -4650,7 +4652,7 @@ public class ProfileUtilities extends TranslatingUtilities { // this is allowed if we only profile the extensions StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs("Element")); if (profile==null) - throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getWorkingCode()) + " in element " + ed.getPath()); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE__IN_ELEMENT_, sdNs(ed.getType().get(0).getWorkingCode()), ed.getPath())); ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), "Element", child.getSelf().getPath().length(), cmp.name); // throw new Error("Not handled yet (sortElements: "+ed.getPath()+":"+typeCode(ed.getType())+")"); } @@ -4719,9 +4721,9 @@ public class ProfileUtilities extends TranslatingUtilities { // generate schematrons for the rules in a structure definition public void generateSchematrons(OutputStream dest, StructureDefinition structure) throws IOException, DefinitionException { if (structure.getDerivation() != TypeDerivationRule.CONSTRAINT) - throw new DefinitionException("not the right kind of structure to generate schematrons for"); + throw new DefinitionException(context.formatMessage(I18nConstants.NOT_THE_RIGHT_KIND_OF_STRUCTURE_TO_GENERATE_SCHEMATRONS_FOR)); if (!structure.hasSnapshot()) - throw new DefinitionException("needs a snapshot"); + throw new DefinitionException(context.formatMessage(I18nConstants.NEEDS_A_SNAPSHOT)); StructureDefinition base = context.fetchResource(StructureDefinition.class, structure.getBaseDefinition()); @@ -4737,7 +4739,7 @@ public class ProfileUtilities extends TranslatingUtilities { // generate a CSV representation of the structure definition public void generateCsvs(OutputStream dest, StructureDefinition structure, boolean asXml) throws IOException, DefinitionException, Exception { if (!structure.hasSnapshot()) - throw new DefinitionException("needs a snapshot"); + throw new DefinitionException(context.formatMessage(I18nConstants.NEEDS_A_SNAPSHOT)); CSVWriter csv = new CSVWriter(dest, structure, asXml); @@ -4753,7 +4755,7 @@ public class ProfileUtilities extends TranslatingUtilities { System.out.println("no structure!"); } if (!structure.hasSnapshot()) { - throw new DefinitionException("needs a snapshot"); + throw new DefinitionException(context.formatMessage(I18nConstants.NEEDS_A_SNAPSHOT)); } XLSXWriter xlsx = new XLSXWriter(dest, structure, asXml, hideMustSupportFalse); @@ -4913,7 +4915,7 @@ public class ProfileUtilities extends TranslatingUtilities { for (ElementDefinition ed : list) { List paths = new ArrayList(); if (!ed.hasPath()) - throw new DefinitionException("No path on element Definition "+Integer.toString(list.indexOf(ed))+" in "+name); + throw new DefinitionException(context.formatMessage(I18nConstants.NO_PATH_ON_ELEMENT_DEFINITION__IN_, Integer.toString(list.indexOf(ed)), name)); sliceInfo.seeElement(ed); String[] pl = ed.getPath().split("\\."); for (int i = paths.size(); i < pl.length; i++) // -1 because the last path is in focus @@ -4937,7 +4939,7 @@ public class ProfileUtilities extends TranslatingUtilities { ed.setId(bs); if (idList.containsKey(bs)) { if (exception || messages == null) { - throw new DefinitionException("Same id '"+bs+"'on multiple elements "+idList.get(bs)+"/"+ed.getPath()+" in "+name); + throw new DefinitionException(context.formatMessage(I18nConstants.SAME_ID_ON_MULTIPLE_ELEMENTS__IN_, bs, idList.get(bs), ed.getPath(), name)); } else messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, name+"."+bs, "Duplicate Element id "+bs, ValidationMessage.IssueSeverity.ERROR)); } @@ -5131,7 +5133,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (sd.hasBaseDefinition()) { StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); if (base == null) - throw new FHIRException("Unable to find base definition for logical model: "+sd.getBaseDefinition()+" from "+sd.getUrl()); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_BASE_DEFINITION_FOR_LOGICAL_MODEL__FROM_, sd.getBaseDefinition(), sd.getUrl())); copyElements(sd, base.getSnapshot().getElement()); } copyElements(sd, sd.getDifferential().getElement()); @@ -5223,7 +5225,7 @@ public class ProfileUtilities extends TranslatingUtilities { else if (slicer.getPath().equals("Bundle.entry")) slicer.getSlicing().addDiscriminator().setType(DiscriminatorType.VALUE).setPath("resource.@profile"); else - throw new Error("No slicing for "+slicer.getPath()); + throw new Error("No slicing for "+slicer.getPath()); } public class SpanEntry { @@ -5342,7 +5344,7 @@ public class ProfileUtilities extends TranslatingUtilities { ElementDefinition ned = ed; while (ned != null && ned.getPath().contains(".")) { ned = findParent(ned, list); - if (ned != null) { // todo: this can happen if we've walked into a resoruce. Not sure what to about that? + if (ned != null) { // todo: this can happen if we've walked into a resoruce. Not sure what to about that? if ("0".equals(ned.getMax())) max = 0; else if (!ned.getMax().equals("1") && !ned.hasSlicing()) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index 867f39771..aed8018b4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -22,17 +22,18 @@ package org.hl7.fhir.r5.context; import java.io.FileNotFoundException; import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.ResourceBundle; import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -41,7 +42,6 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.context.BaseWorkerContext.MetadataResourceVersionComparator; import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory; import org.hl7.fhir.r5.context.TerminologyCache.CacheToken; import org.hl7.fhir.r5.model.BooleanType; @@ -82,6 +82,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple; import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.client.ToolingClientLogger; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.OIDUtils; import org.hl7.fhir.utilities.TranslationServices; import org.hl7.fhir.utilities.Utilities; @@ -95,6 +96,7 @@ import com.google.gson.JsonObject; public abstract class BaseWorkerContext implements IWorkerContext { + private ResourceBundle i18Nmessages; private Locale locale; public class MetadataResourceVersionComparator implements Comparator { @@ -166,19 +168,23 @@ public abstract class BaseWorkerContext implements IWorkerContext { private boolean tlogging = true; public BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException { - super(); txCache = new TerminologyCache(lock, null); + setValidationMessageLanguage(getLocale()); } - public BaseWorkerContext(CanonicalResourceManager codeSystems, CanonicalResourceManager valueSets, CanonicalResourceManager maps, CanonicalResourceManager profiles, + public BaseWorkerContext(Locale locale) throws FileNotFoundException, IOException, FHIRException { + txCache = new TerminologyCache(lock, null); + setValidationMessageLanguage(locale); + } + + public BaseWorkerContext(CanonicalResourceManager codeSystems, CanonicalResourceManager valueSets, CanonicalResourceManager maps, CanonicalResourceManager profiles, CanonicalResourceManager guides) throws FileNotFoundException, IOException, FHIRException { - super(); + this(); this.codeSystems = codeSystems; this.valueSets = valueSets; this.maps = maps; this.structures = profiles; this.guides = guides; - txCache = new TerminologyCache(lock, null); } protected void copy(BaseWorkerContext other) { @@ -232,7 +238,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) { return; } - throw new DefinitionException("Duplicate Resource " + url); + throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url)); } if (r instanceof StructureDefinition) structures.see((StructureDefinition) m); @@ -306,7 +312,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { return laterVersion(newParts[i], oldParts[i]); } // This should never happen - throw new Error("Delimited versions have exact match for delimiter '"+delimiter+"' : "+newParts+" vs "+oldParts); + throw new Error(formatMessage(I18nConstants.DELIMITED_VERSIONS_HAVE_EXACT_MATCH_FOR_DELIMITER____VS_, delimiter, newParts, oldParts)); } protected void seeMetadataResource(T r, Map map, List list, boolean addId) throws FHIRException { @@ -420,25 +426,12 @@ public abstract class BaseWorkerContext implements IWorkerContext { this.expandCodesLimit = expandCodesLimit; } - @Override - public Locale getLocale() { - if (Objects.nonNull(locale)){ - return locale; - } else { - return Locale.US; - } - } - - @Override - public void setLocale(Locale locale) { - this.locale = locale; - } @Override public ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heirarchical) throws FHIRException { ValueSet vs = null; vs = fetchResource(ValueSet.class, binding.getValueSet()); if (vs == null) - throw new FHIRException("Unable to resolve value Set "+binding.getValueSet()); + throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_VALUE_SET_, binding.getValueSet())); return expandVS(vs, cacheOk, heirarchical); } @@ -457,7 +450,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { p.setParameter("excludeNested", !hierarchical); if (noTerminologyServer) - return new ValueSetExpansionOutcome("Error expanding ValueSet: running without terminology services", TerminologyServiceErrorClass.NOSERVICE); + return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE); Map params = new HashMap(); params.put("_limit", Integer.toString(expandCodesLimit )); params.put("_incomplete", "true"); @@ -477,19 +470,19 @@ public abstract class BaseWorkerContext implements IWorkerContext { @Override public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical) { if (expParameters == null) - throw new Error("No Expansion Parameters provided"); + throw new Error(formatMessage(I18nConstants.NO_EXPANSION_PARAMETERS_PROVIDED)); Parameters p = expParameters.copy(); return expandVS(vs, cacheOk, heirarchical, p); } public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, Parameters p) { if (p == null) - throw new Error("No Parameters provided to expandVS"); + throw new Error(formatMessage(I18nConstants.NO_PARAMETERS_PROVIDED_TO_EXPANDVS)); if (vs.hasExpansion()) { return new ValueSetExpansionOutcome(vs.copy()); } if (!vs.hasUrl()) - throw new Error("no value set"); + throw new Error(formatMessage(I18nConstants.NO_VALUE_SET)); CacheToken cacheToken = txCache.generateExpandToken(vs, heirarchical); ValueSetExpansionOutcome res; @@ -506,7 +499,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { ValueSetExpanderSimple vse = new ValueSetExpanderSimple(this); res = vse.doExpand(vs, p); if (!res.getValueset().hasUrl()) - throw new Error("no url in expand value set"); + throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET)); txCache.cacheExpansion(cacheToken, res, TerminologyCache.TRANSIENT); return res; } catch (Exception e) { @@ -514,7 +507,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { // if that failed, we try to expand on the server if (noTerminologyServer) - return new ValueSetExpansionOutcome("Error expanding ValueSet: running without terminology services", TerminologyServiceErrorClass.NOSERVICE); + return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE); Map params = new HashMap(); params.put("_limit", Integer.toString(expandCodesLimit )); params.put("_incomplete", "true"); @@ -524,7 +517,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { if (!result.hasUrl()) result.setUrl(vs.getUrl()); if (!result.hasUrl()) - throw new Error("no url in expand value set 2"); + throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET_2)); res = new ValueSetExpansionOutcome(result).setTxLink(txLog.getLastId()); } catch (Exception e) { res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN).setTxLink(txLog == null ? null : txLog.getLastId()); @@ -584,12 +577,12 @@ public abstract class BaseWorkerContext implements IWorkerContext { } if (!options.isUseServer()) { - return new ValidationResult(IssueSeverity.WARNING, "Unable to validate code without using server", TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS); + return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS); } // if that failed, we try to validate on the server if (noTerminologyServer) { - return new ValidationResult(IssueSeverity.ERROR, "Error validating code: running without terminology services", TerminologyServiceErrorClass.NOSERVICE); + return new ValidationResult(IssueSeverity.ERROR,formatMessage(I18nConstants.ERROR_VALIDATING_CODE_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE); } String csumm = txCache != null ? txCache.summary(code) : null; if (txCache != null) { @@ -664,15 +657,15 @@ public abstract class BaseWorkerContext implements IWorkerContext { pin.addParameter().setName("valueSet").setResource(vs); for (ParametersParameterComponent pp : pin.getParameter()) if (pp.getName().equals("profile")) - throw new Error("Can only specify profile in the context"); + throw new Error(formatMessage(I18nConstants.CAN_ONLY_SPECIFY_PROFILE_IN_THE_CONTEXT)); if (expParameters == null) - throw new Error("No ExpansionProfile provided"); + throw new Error(formatMessage(I18nConstants.NO_EXPANSIONPROFILE_PROVIDED)); pin.addParameter().setName("profile").setResource(expParameters); if (txLog != null) { txLog.clearLastId(); } if (txClient == null) { - throw new FHIRException("Attempt to use Terminology server when no Terminology server is available"); + throw new FHIRException(formatMessage(I18nConstants.ATTEMPT_TO_USE_TERMINOLOGY_SERVER_WHEN_NO_TERMINOLOGY_SERVER_IS_AVAILABLE)); } Parameters pOut; if (vs == null) @@ -879,7 +872,7 @@ public abstract class BaseWorkerContext implements IWorkerContext { } if (supportedCodeSystems.contains(uri)) return null; - throw new FHIRException("not done yet: can't fetch "+uri); + throw new FHIRException(formatMessage(I18nConstants.NOT_DONE_YET_CANT_FETCH_, uri)); } } @@ -925,10 +918,10 @@ public abstract class BaseWorkerContext implements IWorkerContext { if (parts.length >= 2) { if (!Utilities.noString(type)) if (!type.equals(parts[parts.length-2])) - throw new Error("Resource type mismatch for "+type+" / "+uri); + throw new Error(formatMessage(I18nConstants.RESOURCE_TYPE_MISMATCH_FOR___, type, uri)); return allResourcesById.get(parts[parts.length-2]).get(parts[parts.length-1]); } else - throw new Error("Unable to process request for resource for "+type+" / "+uri); + throw new Error(formatMessage(I18nConstants.UNABLE_TO_PROCESS_REQUEST_FOR_RESOURCE_FOR___, type, uri)); } } @@ -1288,5 +1281,36 @@ public abstract class BaseWorkerContext implements IWorkerContext { return binaries; } + @Override + public Locale getLocale() { + if (Objects.nonNull(locale)){ + return locale; + } else { + return Locale.US; + } + } + @Override + public void setLocale(Locale locale) { + this.locale = locale; + setValidationMessageLanguage(getLocale()); + } + + @Override + public String formatMessage(String theMessage, Object... theMessageArguments) { + String message = theMessage; + if (Objects.nonNull(i18Nmessages) && i18Nmessages.containsKey(theMessage)) { + if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) { + message = MessageFormat.format(i18Nmessages.getString(theMessage), theMessageArguments); + } else { + message = i18Nmessages.getString(theMessage); + } + } + return message; + } + + @Override + public void setValidationMessageLanguage(Locale locale) { + i18Nmessages = ResourceBundle.getBundle("Messages", locale); + } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index 0b500b26e..aa9143962 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -326,13 +326,17 @@ public interface IWorkerContext { * @return * @throws FHIRException */ - public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean hierarchical) throws TerminologyServiceException; + ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean hierarchical) throws TerminologyServiceException; - Locale getLocale(); + Locale getLocale(); - void setLocale(Locale locale); + void setLocale(Locale locale); - public class ValidationResult { + String formatMessage(String theMessage, Object... theMessageArguments); + + void setValidationMessageLanguage(Locale locale); + + class ValidationResult { private ConceptDefinitionComponent definition; private IssueSeverity severity; private String message; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index 455dc659f..04aa00fc3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -35,6 +35,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; @@ -72,6 +73,7 @@ import org.hl7.fhir.r5.utils.INarrativeGenerator; import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.NarrativeGenerator; import org.hl7.fhir.utilities.CSFileInputStream; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.cache.NpmPackage; @@ -117,11 +119,20 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon public SimpleWorkerContext() throws FileNotFoundException, IOException, FHIRException { super(); } + + public SimpleWorkerContext(Locale locale) throws FileNotFoundException, IOException, FHIRException { + super(locale); + } public SimpleWorkerContext(SimpleWorkerContext other) throws FileNotFoundException, IOException, FHIRException { super(); copy(other); } + + public SimpleWorkerContext(SimpleWorkerContext other, Locale locale) throws FileNotFoundException, IOException, FHIRException { + super(locale); + copy(other); + } protected void copy(SimpleWorkerContext other) { super.copy(other); @@ -249,7 +260,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon txClient.setLogger(txLog); return txClient.getCapabilitiesStatementQuick().getSoftware().getVersion(); } catch (Exception e) { - throw new FHIRException("Unable to connect to terminology server. Use parameter '-tx n/a' tun run without using terminology services to validate LOINC, SNOMED, ICD-X etc. Error = "+e.getMessage(), e); + throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER_USE_PARAMETER_TX_NA_TUN_RUN_WITHOUT_USING_TERMINOLOGY_SERVICES_TO_VALIDATE_LOINC_SNOMED_ICDX_ETC_ERROR__, e.getMessage()), e); } } @@ -267,9 +278,9 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon f = xml.parse(stream); } } catch (DataFormatException e1) { - throw new org.hl7.fhir.exceptions.FHIRFormatError("Error parsing "+name+":" +e1.getMessage(), e1); + throw new org.hl7.fhir.exceptions.FHIRFormatError(formatMessage(I18nConstants.ERROR_PARSING_, name, e1.getMessage()), e1); } catch (Exception e1) { - throw new org.hl7.fhir.exceptions.FHIRFormatError("Error parsing "+name+":" +e1.getMessage(), e1); + throw new org.hl7.fhir.exceptions.FHIRFormatError(formatMessage(I18nConstants.ERROR_PARSING_, name, e1.getMessage()), e1); } if (f instanceof Bundle) { Bundle bnd = (Bundle) f; @@ -325,7 +336,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon try { loadDefinitionItem(s, pi.load("package", s), loader, filter); } catch (FHIRException | IOException e) { - throw new FHIRException("Error reading "+s+" from package "+pi.name()+"#"+pi.version()+": "+e.getMessage(), e); + throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, s, pi.name(), pi.version(), e.getMessage()), e); } } for (String s : pi.list("other")) { @@ -377,7 +388,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon if (version == null) version = s.substring(8); else if (!version.equals(s.substring(8))) - throw new DefinitionException("Version mismatch. The context has version "+version+" loaded, and the new content being loaded is version "+s.substring(8)); + throw new DefinitionException(formatMessage(I18nConstants.VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_, version, s.substring(8))); } if (s.startsWith("revision=")) revision = s.substring(9); @@ -397,7 +408,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon case JSON: return newJsonParser(); case XML: return newXmlParser(); default: - throw new Error("Parser Type "+type.toString()+" not supported"); + throw new Error(formatMessage(I18nConstants.PARSER_TYPE__NOT_SUPPORTED, type.toString())); } } @@ -407,7 +418,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon return new JsonParser(); if (type.equalsIgnoreCase("XML")) return new XmlParser(); - throw new Error("Parser Type "+type.toString()+" not supported"); + throw new Error(formatMessage(I18nConstants.PARSER_TYPE__NOT_SUPPORTED, type.toString())); } @Override @@ -427,7 +438,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon @Override public IResourceValidator newValidator() throws FHIRException { if (validatorFactory == null) - throw new Error("No validator configured"); + throw new Error(formatMessage(I18nConstants.NO_VALIDATOR_CONFIGURED)); return validatorFactory.makeValidator(this); } @@ -655,13 +666,13 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon public void generateSnapshot(StructureDefinition p, boolean logical) throws DefinitionException, FHIRException { if (!p.hasSnapshot() && (logical || p.getKind() != StructureDefinitionKind.LOGICAL)) { if (!p.hasBaseDefinition()) - throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+") has no base and no snapshot"); + throw new DefinitionException(formatMessage(I18nConstants.PROFILE___HAS_NO_BASE_AND_NO_SNAPSHOT, p.getName(), p.getUrl())); StructureDefinition sd = fetchResource(StructureDefinition.class, p.getBaseDefinition()); if (sd == null && "http://hl7.org/fhir/StructureDefinition/Base".equals(p.getBaseDefinition())) { sd = ProfileUtilities.makeBaseDefinition(p.getFhirVersion()); } if (sd == null) { - throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+") base "+p.getBaseDefinition()+" could not be resolved"); + throw new DefinitionException(formatMessage(I18nConstants.PROFILE___BASE__COULD_NOT_BE_RESOLVED, p.getName(), p.getUrl(), p.getBaseDefinition())); } List msgs = new ArrayList(); List errors = new ArrayList(); @@ -677,10 +688,10 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon pu.generateSnapshot(sd, p, p.getUrl(), Utilities.extractBaseUrl(sd.getUserString("path")), p.getName()); for (ValidationMessage msg : msgs) { if ((!ignoreProfileErrors && msg.getLevel() == ValidationMessage.IssueSeverity.ERROR) || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL) - throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+"), element "+msg.getLocation()+". Error generating snapshot: "+msg.getMessage()); + throw new DefinitionException(formatMessage(I18nConstants.PROFILE___ELEMENT__ERROR_GENERATING_SNAPSHOT_, p.getName(), p.getUrl(), msg.getLocation(), msg.getMessage())); } if (!p.hasSnapshot()) - throw new FHIRException("Profile "+p.getName()+" ("+p.getUrl()+"). Error generating snapshot"); + throw new FHIRException(formatMessage(I18nConstants.PROFILE___ERROR_GENERATING_SNAPSHOT, p.getName(), p.getUrl())); pu = null; } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index b73730ae1..68e1441bd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -9,9 +9,9 @@ package org.hl7.fhir.r5.elementmodel; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -45,6 +45,7 @@ import org.hl7.fhir.r5.formats.JsonCreatorCanonical; import org.hl7.fhir.r5.formats.JsonCreatorGson; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.json.JsonTrackingParser; @@ -90,20 +91,20 @@ public class JsonParser extends ParserBase { map = new IdentityHashMap(); String source = TextFile.streamToString(stream); if (policy == ValidationPolicy.EVERYTHING) { - JsonObject obj = null; + JsonObject obj = null; try { obj = JsonTrackingParser.parse(source, map); - } catch (Exception e) { - logError(-1, -1, "(document)", IssueType.INVALID, "Error parsing JSON: "+e.getMessage(), IssueSeverity.FATAL); + } catch (Exception e) { + logError(-1, -1,context.formatMessage(I18nConstants.DOCUMENT), IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_, e.getMessage()), IssueSeverity.FATAL); return null; } assert (map.containsKey(obj)); - return parse(obj); + return parse(obj); } else { JsonObject obj = JsonTrackingParser.parse(source, null); // (JsonObject) new com.google.gson.JsonParser().parse(source); // assert (map.containsKey(obj)); - return parse(obj); - } + return parse(obj); + } } public Element parse(JsonObject object, Map map) throws FHIRException { @@ -114,7 +115,7 @@ public class JsonParser extends ParserBase { public Element parse(JsonObject object) throws FHIRException { JsonElement rt = object.get("resourceType"); if (rt == null) { - logError(line(object), col(object), "$", IssueType.INVALID, "Unable to find resourceType property", IssueSeverity.FATAL); + logError(line(object), col(object), "$", IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL); return null; } else { String name = rt.getAsString(); @@ -144,13 +145,13 @@ public class JsonParser extends ParserBase { // } } if (!found) - logError(line(object), col(object), path, IssueType.INVALID, "Object must have some content", IssueSeverity.ERROR); + logError(line(object), col(object), path, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR); } } - private void parseChildren(String path, JsonObject object, Element context, boolean hasResourceType) throws FHIRException { - reapComments(object, context); - List properties = context.getProperty().getChildProperties(context.getName(), null); + private void parseChildren(String path, JsonObject object, Element element, boolean hasResourceType) throws FHIRException { + reapComments(object, element); + List properties = element.getProperty().getChildProperties(element.getName(), null); Set processed = new HashSet(); if (hasResourceType) processed.add("resourceType"); @@ -159,14 +160,14 @@ public class JsonParser extends ParserBase { // note that we do not trouble ourselves to maintain the wire format order here - we don't even know what it was anyway // first pass: process the properties for (Property property : properties) { - parseChildItem(path, object, context, processed, property); + parseChildItem(path, object, element, processed, property); } // second pass: check for things not processed if (policy != ValidationPolicy.NONE) { for (Entry e : object.entrySet()) { if (!processed.contains(e.getKey())) { - logError(line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, "Unrecognised property '@"+e.getKey()+"'", IssueSeverity.ERROR); + logError(line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR); } } } @@ -191,7 +192,7 @@ public class JsonParser extends ParserBase { } } - private void parseChildComplex(String path, JsonObject object, Element context, Set processed, Property property, String name) throws FHIRException { + private void parseChildComplex(String path, JsonObject object, Element element, Set processed, Property property, String name) throws FHIRException { processed.add(name); String npath = path+"."+property.getName(); JsonElement e = object.get(name); @@ -199,14 +200,14 @@ public class JsonParser extends ParserBase { JsonArray arr = (JsonArray) e; int c = 0; for (JsonElement am : arr) { - parseChildComplexInstance(npath+"["+c+"]", object, context, property, name, am); + parseChildComplexInstance(npath+"["+c+"]", object, element, property, name, am); c++; } } else { if (property.isList()) { - logError(line(e), col(e), npath, IssueType.INVALID, "This property must be an Array, not "+describeType(e), IssueSeverity.ERROR); + logError(line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describeType(e)), IssueSeverity.ERROR); } - parseChildComplexInstance(npath, object, context, property, name, e); + parseChildComplexInstance(npath, object, element, property, name, e); } } @@ -222,20 +223,20 @@ public class JsonParser extends ParserBase { return null; } - private void parseChildComplexInstance(String npath, JsonObject object, Element context, Property property, String name, JsonElement e) throws FHIRException { + private void parseChildComplexInstance(String npath, JsonObject object, Element element, Property property, String name, JsonElement e) throws FHIRException { if (e instanceof JsonObject) { JsonObject child = (JsonObject) e; Element n = new Element(name, property).markLocation(line(child), col(child)); checkObject(child, npath); - context.getChildren().add(n); + element.getChildren().add(n); if (property.isResource()) parseResource(npath, child, n, property); else parseChildren(npath, child, n, false); - } else - logError(line(e), col(e), npath, IssueType.INVALID, "This property must be "+(property.isList() ? "an Array" : "an Object")+", not "+describe(e), IssueSeverity.ERROR); + } else + logError(line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE__NOT_, (property.isList() ? "an Array" : "an Object"), describe(e)), IssueSeverity.ERROR); } - + private String describe(JsonElement e) { if (e instanceof JsonArray) { return "an array"; @@ -246,21 +247,21 @@ public class JsonParser extends ParserBase { return "a primitive property"; } - private void parseChildPrimitive(JsonObject object, Element context, Set processed, Property property, String path, String name) throws FHIRException { + private void parseChildPrimitive(JsonObject object, Element element, Set processed, Property property, String path, String name) throws FHIRException { String npath = path+"."+property.getName(); processed.add(name); processed.add("_"+name); - JsonElement main = object.has(name) ? object.get(name) : null; + JsonElement main = object.has(name) ? object.get(name) : null; JsonElement fork = object.has("_"+name) ? object.get("_"+name) : null; if (main != null || fork != null) { if (property.isList()) { boolean ok = true; if (!(main == null || main instanceof JsonArray)) { - logError(line(main), col(main), npath, IssueType.INVALID, "This property must be an Array, not a "+describe(main), IssueSeverity.ERROR); + logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_A_, describe(main)), IssueSeverity.ERROR); ok = false; } if (!(fork == null || fork instanceof JsonArray)) { - logError(line(fork), col(fork), npath, IssueType.INVALID, "This base property must be an Array, not a "+describe(main), IssueSeverity.ERROR); + logError(line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_BASE_PROPERTY_MUST_BE_AN_ARRAY_NOT_A_, describe(main)), IssueSeverity.ERROR); ok = false; } if (ok) { @@ -269,11 +270,11 @@ public class JsonParser extends ParserBase { for (int i = 0; i < Math.max(arrC(arr1), arrC(arr2)); i++) { JsonElement m = arrI(arr1, i); JsonElement f = arrI(arr2, i); - parseChildPrimitiveInstance(context, property, name, npath, m, f); + parseChildPrimitiveInstance(element, property, name, npath, m, f); } } } else { - parseChildPrimitiveInstance(context, property, name, npath, main, fork); + parseChildPrimitiveInstance(element, property, name, npath, main, fork); } } } @@ -286,15 +287,16 @@ public class JsonParser extends ParserBase { return arr == null ? 0 : arr.size(); } - private void parseChildPrimitiveInstance(Element context, Property property, String name, String npath, + private void parseChildPrimitiveInstance(Element element, Property property, String name, String npath, JsonElement main, JsonElement fork) throws FHIRException { if (main != null && !(main instanceof JsonPrimitive)) - logError(line(main), col(main), npath, IssueType.INVALID, "This property must be an simple value, not "+describe(main), IssueSeverity.ERROR); + logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage( + I18nConstants.THIS_PROPERTY_MUST_BE_AN_SIMPLE_VALUE_NOT_, describe(main)), IssueSeverity.ERROR); else if (fork != null && !(fork instanceof JsonObject)) - logError(line(fork), col(fork), npath, IssueType.INVALID, "This property must be an object, not "+describe(fork), IssueSeverity.ERROR); + logError(line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(fork)), IssueSeverity.ERROR); else { Element n = new Element(name, property).markLocation(line(main != null ? main : fork), col(main != null ? main : fork)); - context.getChildren().add(n); + element.getChildren().add(n); if (main != null) { JsonPrimitive p = (JsonPrimitive) main; if (p.isNumber() && p.getAsNumber() instanceof JsonTrackingParser.PresentedBigDecimal) { @@ -307,19 +309,19 @@ public class JsonParser extends ParserBase { try { n.setXhtml(new XhtmlParser().setValidatorMode(policy == ValidationPolicy.EVERYTHING).parse(n.getValue(), null).getDocumentElement()); } catch (Exception e) { - logError(line(main), col(main), npath, IssueType.INVALID, "Error parsing XHTML: "+e.getMessage(), IssueSeverity.ERROR); + logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_XHTML_, e.getMessage()), IssueSeverity.ERROR); } } if (policy == ValidationPolicy.EVERYTHING) { // now we cross-check the primitive format against the stated type if (Utilities.existsInList(n.getType(), "boolean")) { if (!p.isBoolean()) - logError(line(main), col(main), npath, IssueType.INVALID, "Error parsing JSON: the primitive value must be a boolean", IssueSeverity.ERROR); + logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_BOOLEAN), IssueSeverity.ERROR); } else if (Utilities.existsInList(n.getType(), "integer", "unsignedInt", "positiveInt", "decimal")) { if (!p.isNumber()) - logError(line(main), col(main), npath, IssueType.INVALID, "Error parsing JSON: the primitive value must be a number", IssueSeverity.ERROR); + logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_NUMBER), IssueSeverity.ERROR); } else if (!p.isString()) - logError(line(main), col(main), npath, IssueType.INVALID, "Error parsing JSON: the primitive value must be a string", IssueSeverity.ERROR); + logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_STRING), IssueSeverity.ERROR); } } if (fork != null) { @@ -334,12 +336,12 @@ public class JsonParser extends ParserBase { private void parseResource(String npath, JsonObject res, Element parent, Property elementProperty) throws FHIRException { JsonElement rt = res.get("resourceType"); if (rt == null) { - logError(line(res), col(res), npath, IssueType.INVALID, "Unable to find resourceType property", IssueSeverity.FATAL); + logError(line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL); } else { String name = rt.getAsString(); StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name, context.getOverrideVersionNs())); if (sd == null) - throw new FHIRFormatError("Contained resource does not appear to be a FHIR resource (unknown name '"+name+"')"); + throw new FHIRFormatError(context.formatMessage(I18nConstants.CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name)); parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(parent.getProperty()), elementProperty); parent.setType(name); parseChildren(npath, res, parent, true); @@ -379,7 +381,7 @@ public class JsonParser extends ParserBase { protected void open(String name, String link) throws IOException { json.link(link); - if (name != null) + if (name != null) json.name(name); json.beginObject(); } @@ -390,7 +392,7 @@ public class JsonParser extends ParserBase { protected void openArray(String name, String link) throws IOException { json.link(link); - if (name != null) + if (name != null) json.name(name); json.beginArray(); } @@ -422,7 +424,7 @@ public class JsonParser extends ParserBase { public void compose(Element e, JsonCreator json) throws Exception { this.json = json; json.beginObject(); - + prop("resourceType", e.getType(), linkResolver == null ? null : linkResolver.resolveProperty(e.getProperty())); Set done = new HashSet(); for (Element child : e.getChildren()) { @@ -450,7 +452,7 @@ public class JsonParser extends ParserBase { if (list.get(0).isPrimitive()) { boolean prim = false; complex = false; - for (Element item : list) { + for (Element item : list) { if (item.hasValue()) prim = true; if (item.hasChildren()) @@ -458,19 +460,19 @@ public class JsonParser extends ParserBase { } if (prim) { openArray(name, linkResolver == null ? null : linkResolver.resolveProperty(list.get(0).getProperty())); - for (Element item : list) { + for (Element item : list) { if (item.hasValue()) primitiveValue(null, item); else json.nullValue(); - } + } closeArray(); } name = "_"+name; } if (complex) { openArray(name, linkResolver == null ? null : linkResolver.resolveProperty(list.get(0).getProperty())); - for (Element item : list) { + for (Element item : list) { if (item.hasChildren()) { open(null,null); if (item.getProperty().isResource()) { @@ -483,9 +485,9 @@ public class JsonParser extends ParserBase { close(); } else json.nullValue(); - } + } closeArray(); - } + } } private void primitiveValue(String name, Element item) throws IOException { @@ -503,10 +505,10 @@ public class JsonParser extends ParserBase { try { json.value(new BigDecimal(item.getValue())); } catch (Exception e) { - throw new NumberFormatException("error writing number '"+item.getValue()+"' to JSON"); + throw new NumberFormatException(context.formatMessage(I18nConstants.ERROR_WRITING_NUMBER__TO_JSON, item.getValue())); } else - json.value(item.getValue()); + json.value(item.getValue()); } private void compose(String path, Element element) throws IOException { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java index 12624b4f3..fe3d4a53d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java @@ -35,6 +35,7 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; @@ -91,11 +92,11 @@ public abstract class ParserBase { protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError { if (ns == null) { - logError(line, col, name, IssueType.STRUCTURE, "This '"+name+"' cannot be parsed as a FHIR object (no namespace)", IssueSeverity.FATAL); + logError(line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS__CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAMESPACE, name), IssueSeverity.FATAL); return null; } if (name == null) { - logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no name)", IssueSeverity.FATAL); + logError(line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAME), IssueSeverity.FATAL); return null; } for (StructureDefinition sd : context.allStructures()) { @@ -107,13 +108,13 @@ public abstract class ParserBase { return sd; } } - logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown namespace/name '"+ns+"::"+name+"')", IssueSeverity.FATAL); + logError(line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAMESPACENAME_, ns, name), IssueSeverity.FATAL); return null; } protected StructureDefinition getDefinition(int line, int col, String name) throws FHIRFormatError { if (name == null) { - logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no name)", IssueSeverity.FATAL); + logError(line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAME), IssueSeverity.FATAL); return null; } // first pass: only look at base definitions @@ -129,7 +130,7 @@ public abstract class ParserBase { return sd; } } - logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown name '"+name+"')", IssueSeverity.FATAL); + logError(line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name), IssueSeverity.FATAL); return null; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java index 5ede6fbd0..ea8f08214 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java @@ -46,6 +46,7 @@ import org.hl7.fhir.r5.utils.formats.Turtle.TTLList; import org.hl7.fhir.r5.utils.formats.Turtle.TTLLiteral; import org.hl7.fhir.r5.utils.formats.Turtle.TTLObject; import org.hl7.fhir.r5.utils.formats.Turtle.TTLURL; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; @@ -69,7 +70,7 @@ public class TurtleParser extends ParserBase { try { src.parse(TextFile.streamToString(input)); } catch (Exception e) { - logError(-1, -1, "(document)", IssueType.INVALID, "Error parsing Turtle: "+e.getMessage(), IssueSeverity.FATAL); + logError(-1, -1, "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_TURTLE_, e.getMessage()), IssueSeverity.FATAL); return null; } return parse(src); @@ -101,7 +102,7 @@ public class TurtleParser extends ParserBase { private Element parse(Turtle src, TTLComplex cmp) throws FHIRException { TTLObject type = cmp.getPredicates().get("http://www.w3.org/2000/01/rdf-schema#type"); if (type == null) { - logError(cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, "Unknown resource type (missing rdfs:type)", IssueSeverity.FATAL); + logError(cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.UNKNOWN_RESOURCE_TYPE_MISSING_RDFSTYPE), IssueSeverity.FATAL); return null; } if (type instanceof TTLList) { @@ -114,7 +115,7 @@ public class TurtleParser extends ParserBase { } } if (!(type instanceof TTLURL)) { - logError(cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, "Unexpected datatype for rdfs:type)", IssueSeverity.FATAL); + logError(cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.UNEXPECTED_DATATYPE_FOR_RDFSTYPE), IssueSeverity.FATAL); return null; } String name = ((TTLURL) type).getUri(); @@ -134,9 +135,9 @@ public class TurtleParser extends ParserBase { return result; } - private void parseChildren(Turtle src, String path, TTLComplex object, Element context, boolean primitive) throws FHIRException { + private void parseChildren(Turtle src, String path, TTLComplex object, Element element, boolean primitive) throws FHIRException { - List properties = context.getProperty().getChildProperties(context.getName(), null); + List properties = element.getProperty().getChildProperties(element.getName(), null); Set processed = new HashSet(); if (primitive) processed.add(FHIR_URI_BASE + "value"); @@ -147,10 +148,10 @@ public class TurtleParser extends ParserBase { if (property.isChoice()) { for (TypeRefComponent type : property.getDefinition().getType()) { String eName = property.getName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getCode()); - parseChild(src, object, context, processed, property, path, getFormalName(property, eName)); + parseChild(src, object, element, processed, property, path, getFormalName(property, eName)); } } else { - parseChild(src, object, context, processed, property, path, getFormalName(property)); + parseChild(src, object, element, processed, property, path, getFormalName(property)); } } @@ -159,7 +160,7 @@ public class TurtleParser extends ParserBase { for (String u : object.getPredicates().keySet()) { if (!processed.contains(u)) { TTLObject n = object.getPredicates().get(u); - logError(n.getLine(), n.getCol(), path, IssueType.STRUCTURE, "Unrecognised predicate '"+u+"'", IssueSeverity.ERROR); + logError(n.getLine(), n.getCol(), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PREDICATE_, u), IssueSeverity.ERROR); } } } @@ -181,13 +182,13 @@ public class TurtleParser extends ParserBase { } } - private void parseChildInstance(Turtle src, String npath, TTLComplex object, Element context, Property property, String name, TTLObject e) throws FHIRException { + private void parseChildInstance(Turtle src, String npath, TTLComplex object, Element element, Property property, String name, TTLObject e) throws FHIRException { if (property.isResource()) - parseResource(src, npath, object, context, property, name, e); + parseResource(src, npath, object, element, property, name, e); else if (e instanceof TTLComplex) { TTLComplex child = (TTLComplex) e; Element n = new Element(tail(name), property).markLocation(e.getLine(), e.getCol()); - context.getChildren().add(n); + element.getChildren().add(n); if (property.isPrimitive(property.getType(tail(name)))) { parseChildren(src, npath, child, n, true); TTLObject val = child.getPredicates().get(FHIR_URI_BASE + "value"); @@ -198,13 +199,13 @@ public class TurtleParser extends ParserBase { // todo: check type n.setValue(value); } else - logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, "This property must be a Literal, not a "+e.getClass().getName(), IssueSeverity.ERROR); + logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_A_LITERAL_NOT_A_, e.getClass().getName()), IssueSeverity.ERROR); } } else parseChildren(src, npath, child, n, false); } else - logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, "This property must be a URI or bnode, not a "+e.getClass().getName(), IssueSeverity.ERROR); + logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_A_URI_OR_BNODE_NOT_A_, e.getClass().getName()), IssueSeverity.ERROR); } @@ -212,7 +213,7 @@ public class TurtleParser extends ParserBase { return name.substring(name.lastIndexOf(".")+1); } - private void parseResource(Turtle src, String npath, TTLComplex object, Element context, Property property, String name, TTLObject e) throws FHIRException { + private void parseResource(Turtle src, String npath, TTLComplex object, Element element, Property property, String name, TTLObject e) throws FHIRException { TTLComplex obj; if (e instanceof TTLComplex) obj = (TTLComplex) e; @@ -220,15 +221,15 @@ public class TurtleParser extends ParserBase { String url = ((TTLURL) e).getUri(); obj = src.getObject(url); if (obj == null) { - logError(e.getLine(), e.getCol(), npath, IssueType.INVALID, "reference to "+url+" cannot be resolved", IssueSeverity.FATAL); + logError(e.getLine(), e.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.REFERENCE_TO__CANNOT_BE_RESOLVED, url), IssueSeverity.FATAL); return; } } else - throw new FHIRFormatError("Wrong type for resource"); + throw new FHIRFormatError(context.formatMessage(I18nConstants.WRONG_TYPE_FOR_RESOURCE)); TTLObject type = obj.getPredicates().get("http://www.w3.org/2000/01/rdf-schema#type"); if (type == null) { - logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, "Unknown resource type (missing rdfs:type)", IssueSeverity.FATAL); + logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNKNOWN_RESOURCE_TYPE_MISSING_RDFSTYPE), IssueSeverity.FATAL); return; } if (type instanceof TTLList) { @@ -241,7 +242,7 @@ public class TurtleParser extends ParserBase { } } if (!(type instanceof TTLURL)) { - logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, "Unexpected datatype for rdfs:type)", IssueSeverity.FATAL); + logError(object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNEXPECTED_DATATYPE_FOR_RDFSTYPE), IssueSeverity.FATAL); return; } String rt = ((TTLURL) type).getUri(); @@ -253,7 +254,7 @@ public class TurtleParser extends ParserBase { return; Element n = new Element(tail(name), property).markLocation(object.getLine(), object.getCol()); - context.getChildren().add(n); + element.getChildren().add(n); n.updateProperty(new Property(this.context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(n.getProperty()), property); n.setType(rt); parseChildren(src, npath, obj, n, false); @@ -278,7 +279,7 @@ public class TurtleParser extends ParserBase { if (en == null) en = property.getDefinition().getPath(); if (!en.endsWith("[x]")) - throw new Error("Attempt to replace element name for a non-choice type"); + throw new Error(context.formatMessage(I18nConstants.ATTEMPT_TO_REPLACE_ELEMENT_NAME_FOR_A_NONCHOICE_TYPE)); return en.substring(0, en.lastIndexOf(".")+1)+elementName; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java index 5592aeef9..c8bf87a03 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java @@ -54,6 +54,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.formats.XmlLocationAnnotator; import org.hl7.fhir.r5.utils.formats.XmlLocationData; import org.hl7.fhir.utilities.ElementDecoration; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; @@ -140,7 +141,8 @@ public class XmlParser extends ParserBase { Node node = document.getFirstChild(); while (node != null) { if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) - logError(line(document), col(document), "(document)", IssueType.INVALID, "No processing instructions allowed in resources", IssueSeverity.ERROR); + logError(line(document), col(document), "(document)", IssueType.INVALID, context.formatMessage( + I18nConstants.NO_PROCESSING_INSTRUCTIONS_ALLOWED_IN_RESOURCES), IssueSeverity.ERROR); node = node.getNextSibling(); } } @@ -214,14 +216,14 @@ public class XmlParser extends ParserBase { private void checkElement(org.w3c.dom.Element element, String path, Property prop) throws FHIRFormatError { if (policy == ValidationPolicy.EVERYTHING) { if (empty(element) && FormatUtilities.FHIR_NS.equals(element.getNamespaceURI())) // this rule only applies to FHIR Content - logError(line(element), col(element), path, IssueType.INVALID, "Element must have some content", IssueSeverity.ERROR); + logError(line(element), col(element), path, IssueType.INVALID, context.formatMessage(I18nConstants.ELEMENT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR); String ns = FormatUtilities.FHIR_NS; if (ToolingExtensions.hasExtension(prop.getDefinition(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace")) ns = ToolingExtensions.readStringExtension(prop.getDefinition(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"); else if (ToolingExtensions.hasExtension(prop.getStructure(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace")) ns = ToolingExtensions.readStringExtension(prop.getStructure(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"); if (!element.getNamespaceURI().equals(ns)) - logError(line(element), col(element), path, IssueType.INVALID, "Wrong namespace - expected '"+ns+"'", IssueSeverity.ERROR); + logError(line(element), col(element), path, IssueType.INVALID, context.formatMessage(I18nConstants.WRONG_NAMESPACE__EXPECTED_, ns), IssueSeverity.ERROR); } } @@ -236,10 +238,10 @@ public class XmlParser extends ParserBase { return result; } - private void parseChildren(String path, org.w3c.dom.Element node, Element context) throws FHIRFormatError, FHIRException, IOException, DefinitionException { + private void parseChildren(String path, org.w3c.dom.Element node, Element element) throws FHIRFormatError, FHIRException, IOException, DefinitionException { // this parsing routine retains the original order in a the XML file, to support validation - reapComments(node, context); - List properties = context.getProperty().getChildProperties(context.getName(), XMLUtil.getXsiType(node)); + reapComments(node, element); + List properties = element.getProperty().getChildProperties(element.getName(), XMLUtil.getXsiType(node)); String text = XMLUtil.getDirectText(node).trim(); if (!Utilities.noString(text)) { @@ -247,17 +249,17 @@ public class XmlParser extends ParserBase { if (property != null) { if ("ED.data[x]".equals(property.getDefinition().getId()) || (property.getDefinition()!=null && property.getDefinition().getBase()!=null && "ED.data[x]".equals(property.getDefinition().getBase().getPath()))) { if ("B64".equals(node.getAttribute("representation"))) { - context.getChildren().add(new Element("dataBase64Binary", property, "base64Binary", text).markLocation(line(node), col(node))); + element.getChildren().add(new Element("dataBase64Binary", property, "base64Binary", text).markLocation(line(node), col(node))); } else { - context.getChildren().add(new Element("dataString", property, "string", text).markLocation(line(node), col(node))); + element.getChildren().add(new Element("dataString", property, "string", text).markLocation(line(node), col(node))); } } else { - context.getChildren().add( + element.getChildren().add( new Element(property.getName(), property, property.getType(), text).markLocation(line(node), col(node))); } } else { - logError(line(node), col(node), path, IssueType.STRUCTURE, "Text should not be present", IssueSeverity.ERROR); + logError(line(node), col(node), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.TEXT_SHOULD_NOT_BE_PRESENT), IssueSeverity.ERROR); } } @@ -269,10 +271,10 @@ public class XmlParser extends ParserBase { String av = attr.getNodeValue(); if (ToolingExtensions.hasExtension(property.getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat")) av = convertForDateFormatFromExternal(ToolingExtensions.readStringExtension(property.getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"), av); - if (property.getName().equals("value") && context.isPrimitive()) - context.setValue(av); + if (property.getName().equals("value") && element.isPrimitive()) + element.setValue(av); else - context.getChildren().add(new Element(property.getName(), property, property.getType(), av).markLocation(line(node), col(node))); + element.getChildren().add(new Element(property.getName(), property, property.getType(), av).markLocation(line(node), col(node))); } else { boolean ok = false; if (FormatUtilities.FHIR_NS.equals(node.getNamespaceURI())) { @@ -281,9 +283,9 @@ public class XmlParser extends ParserBase { } } else ok = ok || (attr.getLocalName().equals("schemaLocation")); // xsi:schemalocation allowed for non FHIR content - ok = ok || (hasTypeAttr(context) && attr.getLocalName().equals("type") && FormatUtilities.NS_XSI.equals(attr.getNamespaceURI())); // xsi:type allowed if element says so + ok = ok || (hasTypeAttr(element) && attr.getLocalName().equals("type") && FormatUtilities.NS_XSI.equals(attr.getNamespaceURI())); // xsi:type allowed if element says so if (!ok) - logError(line(node), col(node), path, IssueType.STRUCTURE, "Undefined attribute '@"+attr.getNodeName()+"' on "+node.getNodeName()+" for type "+context.fhirType()+" (properties = "+properties+")", IssueSeverity.ERROR); + logError(line(node), col(node), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ATTRIBUTE__ON__FOR_TYPE__PROPERTIES__, attr.getNodeName(), node.getNodeName(), element.fhirType(), properties), IssueSeverity.ERROR); } } } @@ -295,11 +297,11 @@ public class XmlParser extends ParserBase { if (property != null) { if (!property.isChoice() && "xhtml".equals(property.getType())) { XhtmlNode xhtml; - if (property.getDefinition().hasRepresentation(PropertyRepresentation.CDATEXT)) + if (property.getDefinition().hasRepresentation(PropertyRepresentation.CDATEXT)) xhtml = new CDANarrativeFormat().convert((org.w3c.dom.Element) child); else xhtml = new XhtmlParser().setValidatorMode(true).parseHtmlNode((org.w3c.dom.Element) child); - context.getChildren().add(new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child), col(child))); + element.getChildren().add(new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child), col(child))); } else { String npath = path+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName(); Element n = new Element(child.getLocalName(), property).markLocation(line(child), col(child)); @@ -313,7 +315,7 @@ public class XmlParser extends ParserBase { xsiType = ToolingExtensions.readStringExtension(property.getDefinition(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-defaulttype"); n.setType(xsiType); } else { - logError(line(child), col(child), path, IssueType.STRUCTURE, "No type found on '"+child.getLocalName()+'"', IssueSeverity.ERROR); + logError(line(child), col(child), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NO_TYPE_FOUND_ON_, child.getLocalName()), IssueSeverity.ERROR); ok = false; } } else { @@ -325,7 +327,7 @@ public class XmlParser extends ParserBase { } else n.setType(n.getType()); } - context.getChildren().add(n); + element.getChildren().add(n); if (ok) { if (property.isResource()) parseResource(npath, (org.w3c.dom.Element) child, n, property); @@ -334,11 +336,11 @@ public class XmlParser extends ParserBase { } } } else - logError(line(child), col(child), path, IssueType.STRUCTURE, "Undefined element '"+child.getLocalName()+"'", IssueSeverity.ERROR); + logError(line(child), col(child), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ELEMENT_, child.getLocalName()), IssueSeverity.ERROR); } else if (child.getNodeType() == Node.CDATA_SECTION_NODE){ - logError(line(child), col(child), path, IssueType.STRUCTURE, "CDATA is not allowed", IssueSeverity.ERROR); + logError(line(child), col(child), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.CDATA_IS_NOT_ALLOWED), IssueSeverity.ERROR); } else if (!Utilities.existsInList(child.getNodeType(), 3, 8)) { - logError(line(child), col(child), path, IssueType.STRUCTURE, "Node type "+Integer.toString(child.getNodeType())+" is not allowed", IssueSeverity.ERROR); + logError(line(child), col(child), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NODE_TYPE__IS_NOT_ALLOWED, Integer.toString(child.getNodeType())), IssueSeverity.ERROR); } child = child.getNextSibling(); } @@ -355,7 +357,8 @@ public class XmlParser extends ParserBase { } }); for (Property p : propsSortedByLongestFirst) - if (!p.getDefinition().hasRepresentation(PropertyRepresentation.XMLATTR) && !p.getDefinition().hasRepresentation(PropertyRepresentation.XMLTEXT)) { + if (!p.getDefinition().hasRepresentation(PropertyRepresentation.XMLATTR) && !p.getDefinition().hasRepresentation( + PropertyRepresentation.XMLTEXT)) { if (p.getName().equals(nodeName)) return p; if (p.getName().endsWith("[x]") && nodeName.length() > p.getName().length()-3 && p.getName().substring(0, p.getName().length()-3).equals(nodeName.substring(0, p.getName().length()-3))) @@ -366,7 +369,8 @@ public class XmlParser extends ParserBase { private Property getAttrProp(List properties, String nodeName) { for (Property p : properties) - if (p.getName().equals(nodeName) && p.getDefinition().hasRepresentation(PropertyRepresentation.XMLATTR)) + if (p.getName().equals(nodeName) && p.getDefinition().hasRepresentation( + PropertyRepresentation.XMLATTR)) return p; return null; } @@ -383,7 +387,7 @@ public class XmlParser extends ParserBase { DateTimeType d = DateTimeType.parseV3(av); return d.asStringValue(); } else - throw new FHIRException("Unknown Data format '"+fmt+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.UNKNOWN_DATA_FORMAT_, fmt)); } private String convertForDateFormatToExternal(String fmt, String av) throws FHIRException { @@ -391,7 +395,7 @@ public class XmlParser extends ParserBase { DateTimeType d = new DateTimeType(av); return d.getAsV3(); } else - throw new FHIRException("Unknown Date format '"+fmt+"'"); + throw new FHIRException(context.formatMessage(I18nConstants.UNKNOWN_DATE_FORMAT_, fmt)); } private void parseResource(String string, org.w3c.dom.Element container, Element parent, Property elementProperty) throws FHIRFormatError, DefinitionException, FHIRException, IOException { @@ -399,7 +403,7 @@ public class XmlParser extends ParserBase { String name = res.getLocalName(); StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name, context.getOverrideVersionNs())); if (sd == null) - throw new FHIRFormatError("Contained resource does not appear to be a FHIR resource (unknown name '"+res.getLocalName()+"')"); + throw new FHIRFormatError(context.formatMessage(I18nConstants.CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, res.getLocalName())); parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(parent.getProperty()), elementProperty); parent.setType(name); parseChildren(res.getLocalName(), res, parent); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index 2cefc64ce..f3bcb334b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -9,9 +9,9 @@ package org.hl7.fhir.r5.terminologies; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -45,6 +45,7 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode; @@ -70,7 +71,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) { for (Coding c : code.getCoding()) { if (!c.hasSystem()) - warnings.add("Coding has no system - cannot validate"); + warnings.add(context.formatMessage(I18nConstants.CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE)); CodeSystem cs = context.fetchCodeSystem(c.getSystem()); ValidationResult res = null; if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) { @@ -90,7 +91,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { ok = ok || codeInValueSet(c.getSystem(), c.getCode()); } if (!ok) - errors.add(0, "None of the provided codes are in the value set "+valueset.getUrl()); + errors.add(0, context.formatMessage(I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl())); } if (errors.size() > 0) return new ValidationResult(IssueSeverity.ERROR, errors.toString()); @@ -138,7 +139,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { if (!inExpansion) res.setMessage("Not in value set "+valueset.getUrl()).setSeverity(IssueSeverity.ERROR); else if (warningMessage!=null) - res = new ValidationResult(IssueSeverity.WARNING, "Code found in expansion, however: " + warningMessage); + res = new ValidationResult(IssueSeverity.WARNING, context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage)); else res.setMessage("Code found in expansion, however: " + res.getMessage()); } @@ -165,7 +166,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { private ValidationResult validateCode(Coding code, CodeSystem cs) { ConceptDefinitionComponent cc = findCodeInConcept(cs.getConcept(), code.getCode()); if (cc == null) - return new ValidationResult(IssueSeverity.ERROR, "Unknown Code "+gen(code)+" in "+cs.getUrl()); + return new ValidationResult(IssueSeverity.ERROR, context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_, gen(code), cs.getUrl())); if (code.getDisplay() == null) return new ValidationResult(cc); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); @@ -193,7 +194,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { return new ValidationResult(cc); } } - return new ValidationResult(IssueSeverity.WARNING, "Display Name for "+code.getSystem()+"#"+code.getCode()+" should be one of '"+b.toString()+"' instead of '"+code.getDisplay()+"'", cc); + return new ValidationResult(IssueSeverity.WARNING, context.formatMessage(I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF_, code.getSystem(), code.getCode(), b.toString(), code.getDisplay()), cc); } private ConceptReferenceComponent findValueSetRef(String system, String code) { @@ -233,25 +234,25 @@ public class ValueSetCheckerSimple implements ValueSetChecker { private String getValueSetSystem() throws FHIRException { if (valueset == null) - throw new FHIRException("Unable to resolve system - no value set"); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__NO_VALUE_SET)); if (valueset.getCompose().hasExclude()) - throw new FHIRException("Unable to resolve system - value set has excludes"); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_EXCLUDES)); if (valueset.getCompose().getInclude().size() == 0) { if (!valueset.hasExpansion() || valueset.getExpansion().getContains().size() == 0) - throw new FHIRException("Unable to resolve system - value set has no includes or expansion"); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_NO_INCLUDES_OR_EXPANSION)); else { String cs = valueset.getExpansion().getContains().get(0).getSystem(); if (cs != null && checkSystem(valueset.getExpansion().getContains(), cs)) return cs; else - throw new FHIRException("Unable to resolve system - value set expansion has multiple systems"); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_EXPANSION_HAS_MULTIPLE_SYSTEMS)); } } for (ConceptSetComponent inc : valueset.getCompose().getInclude()) { if (inc.hasValueSet()) - throw new FHIRException("Unable to resolve system - value set has imports"); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_IMPORTS)); if (!inc.hasSystem()) - throw new FHIRException("Unable to resolve system - value set has include with no system"); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_INCLUDE_WITH_NO_SYSTEM)); } if (valueset.getCompose().getInclude().size() == 1) return valueset.getCompose().getInclude().get(0).getSystem(); @@ -360,7 +361,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { // ok, we need the code system CodeSystem cs = context.fetchCodeSystem(system); if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) { - // make up a transient value set with + // make up a transient value set with ValueSet vs = new ValueSet(); vs.setUrl(Utilities.makeUuidUrn()); vs.getCompose().addInclude(vsi); @@ -395,7 +396,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { return codeInConceptFilter(cs, f, code); else { System.out.println("todo: handle filters with property = "+f.getProperty()); - throw new FHIRException("Unable to handle system "+cs.getUrl()+" filter with property = "+f.getProperty()); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_HANDLE_SYSTEM__FILTER_WITH_PROPERTY__, cs.getUrl(), f.getProperty())); } } @@ -405,7 +406,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { case ISNOTA: return !codeInConceptIsAFilter(cs, f, code); default: System.out.println("todo: handle concept filters with op = "+f.getOp()); - throw new FHIRException("Unable to handle system "+cs.getUrl()+" concept filter with op = "+f.getOp()); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_HANDLE_SYSTEM__CONCEPT_FILTER_WITH_OP__, cs.getUrl(), f.getOp())); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/IResourceValidator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/IResourceValidator.java index 86852318a..bc99d7a0b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/IResourceValidator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/IResourceValidator.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; +import java.util.Locale; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; @@ -68,7 +69,9 @@ public interface IResourceValidator { Element fetch(Object appContext, String url) throws FHIRFormatError, DefinitionException, FHIRException, IOException; ReferenceValidationPolicy validationPolicy(Object appContext, String path, String url); - boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException; + boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException; + + void setLocale(Locale locale); } public enum BestPracticeWarningLevel { @@ -143,9 +146,10 @@ public interface IResourceValidator { public boolean isShowMessagesFromReferences(); public void setShowMessagesFromReferences(boolean value); - - public String getValidationLanguage(); - public void setValidationLanguage(String value); + + //FIXME: don't need that, gets never used? +// public String getValidationLanguage(); +// public void setValidationLanguage(String value); /** * It's common to see references such as Patient/234234 - these usually mean a reference to a Patient resource. diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/utils/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/I18nConstants.java similarity index 58% rename from org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/utils/I18nConstants.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/I18nConstants.java index 2a30f494c..62810d399 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/utils/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/I18nConstants.java @@ -1,4 +1,7 @@ -package org.hl7.fhir.validation.utils; +package org.hl7.fhir.utilities; + +import java.text.MessageFormat; +import java.util.ResourceBundle; public class I18nConstants { @@ -268,5 +271,163 @@ public class I18nConstants { public final static String NOT_DONE_YET_VALIDATORHOSTSERVICESEXECUTEFUNCTION = "Not_done_yet_ValidatorHostServicesexecuteFunction"; public final static String NOT_DONE_YET_VALIDATORHOSTSERVICESCHECKFUNCTION = "Not_done_yet_ValidatorHostServicescheckFunction"; public final static String NOT_DONE_YET_VALIDATORHOSTSERVICESRESOLVEFUNCTION_ = "Not_done_yet_ValidatorHostServicesresolveFunction_"; + public final static String UNABLE_TO_FIND_BASE_DEFINITION_FOR_LOGICAL_MODEL__FROM_ = "Unable_to_find_base_definition_for_logical_model__from_"; + public final static String SAME_ID_ON_MULTIPLE_ELEMENTS__IN_ = "Same_id_on_multiple_elements__in_"; + public final static String NO_PATH_ON_ELEMENT_DEFINITION__IN_ = "No_path_on_element_Definition__in_"; + public final static String NEEDS_A_SNAPSHOT = "needs_a_snapshot"; + public final static String NOT_THE_RIGHT_KIND_OF_STRUCTURE_TO_GENERATE_SCHEMATRONS_FOR = "not_the_right_kind_of_structure_to_generate_schematrons_for"; + public final static String NOT_HANDLED_YET_SORTELEMENTS_ = "Not_handled_yet_sortElements_"; + public final static String UNABLE_TO_RESOLVE_PROFILE__IN_ELEMENT_ = "Unable_to_resolve_profile__in_element_"; + public final static String CANT_HAVE_CHILDREN_ON_AN_ELEMENT_WITH_A_POLYMORPHIC_TYPE__YOU_MUST_SLICE_AND_CONSTRAIN_THE_TYPES_FIRST_SORTELEMENTS_ = "Cant_have_children_on_an_element_with_a_polymorphic_type__you_must_slice_and_constrain_the_types_first_sortElements_"; + public final static String UNABLE_TO_FIND_PROFILE__AT_ = "Unable_to_find_profile__at_"; + public final static String UNHANDLED_SITUATION_RESOURCE_IS_PROFILED_TO_MORE_THAN_ONE_OPTION__CANNOT_SORT_PROFILE = "Unhandled_situation_resource_is_profiled_to_more_than_one_option__cannot_sort_profile"; + public final static String INTERNAL_RECURSION_DETECTION_FIND_LOOP_PATH_RECURSION____CHECK_PATHS_ARE_VALID_FOR_PATH_ = "Internal_recursion_detection_find_loop_path_recursion____check_paths_are_valid_for_path_"; + public final static String INTERNAL_ERROR___TYPE_NOT_KNOWN_ = "Internal_error___type_not_known_"; + public final static String UNABLE_TO_FIND_ELEMENT_ = "Unable_to_find_element_"; + public final static String ERROR_GENERATING_TABLE_FOR_PROFILE__ = "Error_generating_table_for_profile__"; + public final static String STRUCTUREDEFINITION__AT__ILLEGAL_CONSTRAINED_TYPE__FROM__IN_ = "StructureDefinition__at__illegal_constrained_type__from__in_"; + public final static String ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_ = "Error_at__The_target_profile__is_not__valid_constraint_on_the_base_"; + public final static String ERROR_IN_PROFILE__AT__BASE_ISSUMMARY___DERIVED_ISSUMMARY__ = "Error_in_profile__at__Base_isSummary___derived_isSummary__"; + public final static String UNEXPECTED_CONDITION_IN_DIFFERENTIAL_TYPESLICETYPELISTSIZE__1_AT_ = "Unexpected_condition_in_differential_typeslicetypelistsize__1_at_"; + public final static String UNEXPECTED_CONDITION_IN_DIFFERENTIAL_TYPESLICETYPELISTSIZE__10_AND_IMPLICIT_SLICE_NAME_DOES_NOT_CONTAIN_A_VALID_TYPE__AT_ = "Unexpected_condition_in_differential_typeslicetypelistsize__10_and_implicit_slice_name_does_not_contain_a_valid_type__at_"; + public final static String ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED = "Attempt_to_use_a_snapshot_on_profile__as__before_it_is_generated"; + public final static String NULL_MIN = "null_min"; + public final static String _HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE = "_has_children__for_type__in_profile__but_cant_find_type"; + public final static String _HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_ = "_has_children__and_multiple_types__in_profile_"; + public final static String ADDING_WRONG_PATH = "Adding_wrong_path"; + public final static String NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE = "Named_items_are_out_of_order_in_the_slice"; + public final static String THE_BASE_SNAPSHOT_MARKS_A_SLICING_AS_CLOSED_BUT_THE_DIFFERENTIAL_TRIES_TO_EXTEND_IT_IN__AT__ = "The_base_snapshot_marks_a_slicing_as_closed_but_the_differential_tries_to_extend_it_in__at__"; + public final static String NOT_DONE_YET = "Not_done_yet"; + public final static String UNKNOWN_TYPE__AT_ = "Unknown_type__at_"; + public final static String DIFFERENTIAL_WALKS_INTO____BUT_THE_BASE_DOES_NOT_AND_THERE_IS_NOT_A_SINGLE_FIXED_TYPE_THE_TYPE_IS__THIS_IS_NOT_HANDLED_YET = "Differential_walks_into____but_the_base_does_not_and_there_is_not_a_single_fixed_type_The_type_is__This_is_not_handled_yet"; + public final static String SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___ = "Slicing_rules_on_differential__do_not_match_those_on_base___rule___"; + public final static String SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___DISCIMINATOR___ = "Slicing_rules_on_differential__do_not_match_those_on_base___disciminator___"; + public final static String SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___ORDER___ = "Slicing_rules_on_differential__do_not_match_those_on_base___order___"; + public final static String INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST = "Invalid_slicing__there_is_more_than_one_type_slice_at__but_one_of_them__has_min__1_so_the_other_slices_cannot_exist"; + public final static String DID_NOT_FIND_TYPE_ROOT_ = "Did_not_find_type_root_"; + public final static String ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_ = "Error_at_path__Slice_for_type__has_wrong_type_"; + public final static String ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_ = "Error_at_path__Slice_for_type__has_more_than_one_type_"; + public final static String ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_ = "Error_at_path__Slice_name_must_be__but_is_"; + public final static String ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS = "Error_at_path__in__Type_slicing_with_slicingdiscriminatorpath__this"; + public final static String ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE = "Error_at_path__in__Type_slicing_with_slicingdiscriminatortype__type"; + public final static String ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1 = "Error_at_path__in__Type_slicing_with_slicingdiscriminatorcount__1"; + public final static String ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE = "Error_at_path__in__Type_slicing_with_slicingordered__true"; + public final static String ADDING_WRONG_PATH_IN_PROFILE___VS_ = "Adding_wrong_path_in_profile___vs_"; + public final static String _HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_ = "_has_no_children__and_no_types_in_profile_"; + public final static String DID_NOT_FIND_SINGLE_SLICE_ = "Did_not_find_single_slice_"; + public final static String DIFFERENTIAL_DOES_NOT_HAVE_A_SLICE__B_OF_____IN_PROFILE_ = "Differential_does_not_have_a_slice__b_of_____in_profile_"; + public final static String ATTEMPT_TO_A_SLICE_AN_ELEMENT_THAT_DOES_NOT_REPEAT__FROM__IN_ = "Attempt_to_a_slice_an_element_that_does_not_repeat__from__in_"; + public final static String UNABLE_TO_RESOLVE_REFERENCE_TO_ = "Unable_to_resolve_reference_to_"; + public final static String UNABLE_TO_FIND_ELEMENT__IN_ = "Unable_to_find_element__in_"; + public final static String UNABLE_TO_FIND_BASE__FOR_ = "Unable_to_find_base__for_"; + public final static String ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__ = "Adding_wrong_path__outcomegetPath___resultPathBase__"; + public final static String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__ILLEGAL_CHARACTERS_ = "Illegal_path__in_differential_in__illegal_characters_"; + public final static String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__ILLEGAL_CHARACTER_ = "Illegal_path__in_differential_in__illegal_character_"; + public final static String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NO_UNICODE_WHITESPACE = "Illegal_path__in_differential_in__no_unicode_whitespace"; + public final static String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NAME_PORTION_EXCEEDS_64_CHARS_IN_LENGTH = "Illegal_path__in_differential_in__name_portion_exceeds_64_chars_in_length"; + public final static String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NAME_PORTION_MISING_ = "Illegal_path__in_differential_in__name_portion_mising_"; + public final static String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__MUST_START_WITH_ = "Illegal_path__in_differential_in__must_start_with_"; + public final static String NO_PATH_VALUE_ON_ELEMENT_IN_DIFFERENTIAL_IN_ = "No_path_value_on_element_in_differential_in_"; + public final static String NO_PATH_ON_ELEMENT_IN_DIFFERENTIAL_IN_ = "No_path_on_element_in_differential_in_"; + public final static String UNXPECTED_INTERNAL_CONDITION__NO_SOURCE_ON_DIFF_ELEMENT = "Unxpected_internal_condition__no_source_on_diff_element"; + public final static String TYPE_ON_FIRST_SNAPSHOT_ELEMENT_FOR__IN__FROM_ = "type_on_first_snapshot_element_for__in__from_"; + public final static String TYPE_ON_FIRST_DIFFERENTIAL_ELEMENT = "type_on_first_differential_element"; + public final static String CIRCULAR_SNAPSHOT_REFERENCES_DETECTED_CANNOT_GENERATE_SNAPSHOT_STACK__ = "Circular_snapshot_references_detected_cannot_generate_snapshot_stack__"; + public final static String BASE__DERIVED_PROFILES_HAVE_DIFFERENT_TYPES____VS___ = "Base__Derived_profiles_have_different_types____vs___"; + public final static String DERIVED_PROFILE__HAS_NO_DERIVATION_VALUE_AND_SO_CANT_BE_PROCESSED = "Derived_profile__has_no_derivation_value_and_so_cant_be_processed"; + public final static String DERIVED_PROFILE__HAS_NO_TYPE = "Derived_profile__has_no_type"; + public final static String BASE_PROFILE__HAS_NO_TYPE = "Base_profile__has_no_type"; + public final static String NO_DERIVED_STRUCTURE_PROVIDED = "no_derived_structure_provided"; + public final static String NO_BASE_PROFILE_PROVIDED = "no_base_profile_provided"; + public final static String ELEMENT_ID__NULL__ON_ = "element_id__null__on_"; + public final static String ELEMENT__NULL_ = "element__null_"; + public final static String GETSLICELIST_SHOULD_ONLY_BE_CALLED_WHEN_THE_ELEMENT_HAS_SLICING = "getSliceList_should_only_be_called_when_the_element_has_slicing"; + public final static String UNABLE_TO_RESOLVE_NAME_REFERENCE__AT_PATH_ = "Unable_to_resolve_name_reference__at_path_"; + public final static String DETAILS_FOR__MATCHING_AGAINST_PROFILE_ = "Details_for__matching_against_Profile_"; + public final static String DOES_NOT_MATCH_SLICE_ = "Does_not_match_slice_"; + public final static String PROFILE__DOES_NOT_MATCH_FOR__BECAUSE_OF_THE_FOLLOWING_PROFILE_ISSUES__ = "Profile__does_not_match_for__because_of_the_following_profile_issues__"; + public final static String THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_ = "This_element_does_not_match_any_known_slice_"; + public final static String DEFINED_IN_THE_PROFILE = "defined_in_the_profile"; + public final static String THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_ = "This_does_not_appear_to_be_a_FHIR_resource_unknown_name_"; + public final static String THIS_CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAME = "This_cannot_be_parsed_as_a_FHIR_object_no_name"; + public final static String THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAMESPACENAME_ = "This_does_not_appear_to_be_a_FHIR_resource_unknown_namespacename_"; + public final static String THIS__CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAMESPACE = "This__cannot_be_parsed_as_a_FHIR_object_no_namespace"; + public final static String UNABLE_TO_FIND_RESOURCETYPE_PROPERTY = "Unable_to_find_resourceType_property"; + public final static String ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_STRING = "Error_parsing_JSON_the_primitive_value_must_be_a_string"; + public final static String ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_NUMBER = "Error_parsing_JSON_the_primitive_value_must_be_a_number"; + public final static String ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_BOOLEAN = "Error_parsing_JSON_the_primitive_value_must_be_a_boolean"; + public final static String ERROR_PARSING_XHTML_ = "Error_parsing_XHTML_"; + public final static String THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_ = "This_property_must_be_an_object_not_"; + public final static String THIS_PROPERTY_MUST_BE_AN_SIMPLE_VALUE_NOT_ = "This_property_must_be_an_simple_value_not_"; + public final static String THIS_PROPERTY_MUST_BE__NOT_ = "This_property_must_be__not_"; + public final static String THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_ = "This_property_must_be_an_Array_not_"; + public final static String UNRECOGNISED_PROPERTY_ = "Unrecognised_property_"; + public final static String OBJECT_MUST_HAVE_SOME_CONTENT = "Object_must_have_some_content"; + public final static String ERROR_PARSING_JSON_ = "Error_parsing_JSON_"; + public final static String NODE_TYPE__IS_NOT_ALLOWED = "Node_type__is_not_allowed"; + public final static String CDATA_IS_NOT_ALLOWED = "CDATA_is_not_allowed"; + public final static String UNDEFINED_ELEMENT_ = "Undefined_element_"; + public final static String UNDEFINED_ATTRIBUTE__ON__FOR_TYPE__PROPERTIES__ = "Undefined_attribute__on__for_type__properties__"; + public final static String TEXT_SHOULD_NOT_BE_PRESENT = "Text_should_not_be_present"; + public final static String WRONG_NAMESPACE__EXPECTED_ = "Wrong_namespace__expected_"; + public final static String ELEMENT_MUST_HAVE_SOME_CONTENT = "Element_must_have_some_content"; + public final static String NO_PROCESSING_INSTRUCTIONS_ALLOWED_IN_RESOURCES = "No_processing_instructions_allowed_in_resources"; + public final static String UNKNOWN_RESOURCE_TYPE_MISSING_RDFSTYPE = "Unknown_resource_type_missing_rdfstype"; + public final static String REFERENCE_TO__CANNOT_BE_RESOLVED = "reference_to__cannot_be_resolved"; + public final static String THIS_PROPERTY_MUST_BE_A_URI_OR_BNODE_NOT_A_ = "This_property_must_be_a_URI_or_bnode_not_a_"; + public final static String THIS_PROPERTY_MUST_BE_A_LITERAL_NOT_A_ = "This_property_must_be_a_Literal_not_a_"; + public final static String UNRECOGNISED_PREDICATE_ = "Unrecognised_predicate_"; + public final static String ERROR_PARSING_TURTLE_ = "Error_parsing_Turtle_"; + public final static String UNEXPECTED_DATATYPE_FOR_RDFSTYPE = "Unexpected_datatype_for_rdfstype"; + public final static String ATTEMPT_TO_REPLACE_ELEMENT_NAME_FOR_A_NONCHOICE_TYPE = "Attempt_to_replace_element_name_for_a_nonchoice_type"; + public final static String WRONG_TYPE_FOR_RESOURCE = "Wrong_type_for_resource"; + public final static String CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_ = "Contained_resource_does_not_appear_to_be_a_FHIR_resource_unknown_name_"; + public final static String UNKNOWN_DATE_FORMAT_ = "Unknown_Date_format_"; + public final static String UNKNOWN_DATA_FORMAT_ = "Unknown_Data_format_"; + public final static String NO_TYPE_FOUND_ON_ = "No_type_found_on_"; + public final static String ERROR_WRITING_NUMBER__TO_JSON = "error_writing_number__to_JSON"; + public final static String UNABLE_TO_PROCESS_REQUEST_FOR_RESOURCE_FOR___ = "Unable_to_process_request_for_resource_for___"; + public final static String RESOURCE_TYPE_MISMATCH_FOR___ = "Resource_type_mismatch_for___"; + public final static String NOT_DONE_YET_CANT_FETCH_ = "not_done_yet_cant_fetch_"; + public final static String ATTEMPT_TO_USE_TERMINOLOGY_SERVER_WHEN_NO_TERMINOLOGY_SERVER_IS_AVAILABLE = "Attempt_to_use_Terminology_server_when_no_Terminology_server_is_available"; + public final static String NO_EXPANSIONPROFILE_PROVIDED = "No_ExpansionProfile_provided"; + public final static String CAN_ONLY_SPECIFY_PROFILE_IN_THE_CONTEXT = "Can_only_specify_profile_in_the_context"; + public final static String NO_URL_IN_EXPAND_VALUE_SET_2 = "no_url_in_expand_value_set_2"; + public final static String NO_URL_IN_EXPAND_VALUE_SET = "no_url_in_expand_value_set"; + public final static String NO_VALUE_SET = "no_value_set"; + public final static String NO_PARAMETERS_PROVIDED_TO_EXPANDVS = "No_Parameters_provided_to_expandVS"; + public final static String NO_EXPANSION_PARAMETERS_PROVIDED = "No_Expansion_Parameters_provided"; + public final static String UNABLE_TO_RESOLVE_VALUE_SET_ = "Unable_to_resolve_value_Set_"; + public final static String DELIMITED_VERSIONS_HAVE_EXACT_MATCH_FOR_DELIMITER____VS_ = "Delimited_versions_have_exact_match_for_delimiter____vs_"; + public final static String DUPLICATE_RESOURCE_ = "Duplicate_Resource_"; + public final static String ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES = "Error_expanding_ValueSet_running_without_terminology_services"; + public final static String ERROR_VALIDATING_CODE_RUNNING_WITHOUT_TERMINOLOGY_SERVICES = "Error_validating_code_running_without_terminology_services"; + public final static String UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER = "Unable_to_validate_code_without_using_server"; + public final static String PROFILE___ERROR_GENERATING_SNAPSHOT = "Profile___Error_generating_snapshot"; + public final static String PROFILE___ELEMENT__ERROR_GENERATING_SNAPSHOT_ = "Profile___element__Error_generating_snapshot_"; + public final static String PROFILE___BASE__COULD_NOT_BE_RESOLVED = "Profile___base__could_not_be_resolved"; + public final static String PROFILE___HAS_NO_BASE_AND_NO_SNAPSHOT = "Profile___has_no_base_and_no_snapshot"; + public final static String NO_VALIDATOR_CONFIGURED = "No_validator_configured"; + public final static String PARSER_TYPE__NOT_SUPPORTED = "Parser_Type__not_supported"; + public final static String VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_ = "Version_mismatch_The_context_has_version__loaded_and_the_new_content_being_loaded_is_version_"; + public final static String ERROR_READING__FROM_PACKAGE__ = "Error_reading__from_package__"; + public final static String ERROR_PARSING_ = "Error_parsing_"; + public final static String UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER_USE_PARAMETER_TX_NA_TUN_RUN_WITHOUT_USING_TERMINOLOGY_SERVICES_TO_VALIDATE_LOINC_SNOMED_ICDX_ETC_ERROR__ = "Unable_to_connect_to_terminology_server_Use_parameter_tx_na_tun_run_without_using_terminology_services_to_validate_LOINC_SNOMED_ICDX_etc_Error__"; + public final static String DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF_ = "Display_Name_for__should_be_one_of__instead_of_"; + public final static String UNKNOWN_CODE__IN_ = "Unknown_Code__in_"; + public final static String CODE_FOUND_IN_EXPANSION_HOWEVER_ = "Code_found_in_expansion_however_"; + public final static String NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = "None_of_the_provided_codes_are_in_the_value_set_"; + public final static String CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE = "Coding_has_no_system__cannot_validate"; + public final static String UNABLE_TO_HANDLE_SYSTEM__CONCEPT_FILTER_WITH_OP__ = "Unable_to_handle_system__concept_filter_with_op__"; + public final static String UNABLE_TO_HANDLE_SYSTEM__FILTER_WITH_PROPERTY__ = "Unable_to_handle_system__filter_with_property__"; + public final static String UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_INCLUDE_WITH_NO_SYSTEM = "Unable_to_resolve_system__value_set_has_include_with_no_system"; + public final static String UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_IMPORTS = "Unable_to_resolve_system__value_set_has_imports"; + public final static String UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_EXPANSION_HAS_MULTIPLE_SYSTEMS = "Unable_to_resolve_system__value_set_expansion_has_multiple_systems"; + public final static String UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_NO_INCLUDES_OR_EXPANSION = "Unable_to_resolve_system__value_set_has_no_includes_or_expansion"; + public final static String UNABLE_TO_RESOLVE_SYSTEM__VALUE_SET_HAS_EXCLUDES = "Unable_to_resolve_system__value_set_has_excludes"; + public final static String UNABLE_TO_RESOLVE_SYSTEM__NO_VALUE_SET = "Unable_to_resolve_system__no_value_set"; + public final static String THIS_BASE_PROPERTY_MUST_BE_AN_ARRAY_NOT_A_ = "This_base_property_must_be_an_Array_not_a_"; + public final static String THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_A_ = "This_property_must_be_an_Array_not_a_"; + public final static String DOCUMENT = "documentmsg"; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index 1a0b6e97a..e1f616090 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -64,17 +64,16 @@ public class BaseValidator { protected Source source; protected IWorkerContext context; - private ResourceBundle messages; + public BaseValidator(IWorkerContext context){ this.context = context; - messages = ResourceBundle.getBundle("Messages", context.getLocale() ); } - public void setContext(IWorkerContext context) { - this.context = context; - messages = ResourceBundle.getBundle("Messages", context.getLocale() ); - } +// public void setContext(IWorkerContext context) { +// this.context = context; +// i18Nmessages = ResourceBundle.getBundle("Messages", context.getLocale() ); +// } /** * Test a rule and add a {@link IssueSeverity#FATAL} validation message if the validation fails @@ -93,7 +92,7 @@ public class BaseValidator { protected boolean fail(List errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - String msg = formatMessage(theMessage, theMessageArguments); + String msg = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, line, col, path, msg, IssueSeverity.FATAL); } return thePass; @@ -124,7 +123,7 @@ public class BaseValidator { protected boolean fail(List errors, IssueType type, List pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { String path = toPath(pathParts); - addValidationMessage(errors, type, -1, -1, path, formatMessage(theMessage, theMessageArguments), IssueSeverity.FATAL); + addValidationMessage(errors, type, -1, -1, path, context.formatMessage(theMessage, theMessageArguments), IssueSeverity.FATAL); } return thePass; } @@ -143,21 +142,6 @@ public class BaseValidator { return thePass; } - - protected String formatMessage(String theMessage, Object... theMessageArguments) { - String message = ""; - if (messages.containsKey(theMessage)) { - if (theMessageArguments != null && theMessageArguments.length > 0) { - message = MessageFormat.format(messages.getString(theMessage), theMessageArguments); - } else if (messages.containsKey(theMessage)) { - message = messages.getString(theMessage); - } - } else { - message = theMessage; - } - return message; - } - protected boolean grammarWord(String w) { return w.equals("and") || w.equals("or") || w.equals("a") || w.equals("the") || w.equals("for") || w.equals("this") || w.equals("that") || w.equals("of"); } @@ -171,7 +155,7 @@ public class BaseValidator { */ protected boolean hint(List errors, IssueType type, int line, int col, String path, boolean thePass, String msg) { if (!thePass) { - String message = formatMessage(msg); + String message = context.formatMessage(msg); addValidationMessage(errors, type, line, col, path, message, IssueSeverity.INFORMATION); } return thePass; @@ -201,7 +185,7 @@ public class BaseValidator { */ protected boolean hint(List errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, line, col, path, message, IssueSeverity.INFORMATION); } return thePass; @@ -209,7 +193,7 @@ public class BaseValidator { protected boolean txHint(List errors, String txLink, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, line, col, path, message, IssueSeverity.INFORMATION, Source.TerminologyEngine).setTxLink(txLink); } return thePass; @@ -225,7 +209,7 @@ public class BaseValidator { protected boolean hint(List errors, IssueType type, List pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { String path = toPath(pathParts); - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.INFORMATION); } return thePass; @@ -254,7 +238,7 @@ public class BaseValidator { */ protected boolean rule(List errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, line, col, path, message, IssueSeverity.ERROR); } return thePass; @@ -262,7 +246,7 @@ public class BaseValidator { protected boolean txRule(List errors, String txLink, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); errors.add(new ValidationMessage(Source.TerminologyEngine, type, line, col, path, message, IssueSeverity.ERROR).setTxLink(txLink)); } return thePass; @@ -293,7 +277,7 @@ public class BaseValidator { protected boolean rule(List errors, IssueType type, List pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { String path = toPath(pathParts); - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.ERROR); } return thePass; @@ -317,7 +301,7 @@ public class BaseValidator { protected boolean rule(List errors, IssueType type, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.ERROR); } return thePass; @@ -381,7 +365,7 @@ public class BaseValidator { */ protected boolean warning(List errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { if (!thePass) { - msg = formatMessage(msg, theMessageArguments); + msg = context.formatMessage(msg, theMessageArguments); IssueSeverity severity = IssueSeverity.WARNING; addValidationMessage(errors, type, line, col, path, msg, severity); } @@ -409,7 +393,7 @@ public class BaseValidator { */ protected boolean txWarning(List errors, String txLink, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { if (!thePass) { - msg = formatMessage(msg, theMessageArguments); + msg = context.formatMessage(msg, theMessageArguments); errors.add(new ValidationMessage(Source.TerminologyEngine, type, line, col, path, msg, IssueSeverity.WARNING).setTxLink(txLink)); } return thePass; @@ -418,7 +402,7 @@ public class BaseValidator { protected boolean warningOrError(boolean isError, List errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { if (!thePass) { - msg = formatMessage(msg, theMessageArguments); + msg = context.formatMessage(msg, theMessageArguments); addValidationMessage(errors, type, line, col, path, msg, isError ? IssueSeverity.ERROR : IssueSeverity.WARNING); } return thePass; @@ -435,7 +419,7 @@ public class BaseValidator { protected boolean warning(List errors, IssueType type, List pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { String path = toPath(pathParts); - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.WARNING); } return thePass; @@ -478,7 +462,7 @@ public class BaseValidator { */ protected boolean warning(List errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) { if (!thePass) { - msg = formatMessage(msg, theMessageArguments); + msg = context.formatMessage(msg, theMessageArguments); addValidationMessage(errors, type, path, msg, html, IssueSeverity.WARNING); } return thePass; @@ -494,7 +478,7 @@ public class BaseValidator { */ protected boolean suppressedwarning(List errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { if (!thePass) { - msg = formatMessage(msg, theMessageArguments); + msg = context.formatMessage(msg, theMessageArguments); addValidationMessage(errors, type, line, col, path, msg, IssueSeverity.INFORMATION); } return thePass; @@ -511,7 +495,7 @@ public class BaseValidator { protected boolean suppressedwarning(List errors, IssueType type, List pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { String path = toPath(pathParts); - String message = formatMessage(theMessage, theMessageArguments); + String message = context.formatMessage(theMessage, theMessageArguments); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.INFORMATION); } return thePass; @@ -559,7 +543,7 @@ public class BaseValidator { */ protected boolean suppressedwarning(List errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) { if (!thePass) { - msg = formatMessage(msg, theMessageArguments); + msg = context.formatMessage(msg, theMessageArguments); addValidationMessage(errors, type, path, msg, html, IssueSeverity.INFORMATION); } return thePass; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index 0e8d93ecc..3e5a1d91d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -139,6 +139,8 @@ POSSIBILITY OF SUCH DAMAGE. */ public class ValidationEngine implements IValidatorResourceFetcher { + + public class ScanOutputItem { private String ref; private ImplementationGuide ig; @@ -240,6 +242,7 @@ public class ValidationEngine implements IValidatorResourceFetcher { private Set loadedIgs = new HashSet<>(); private IValidatorResourceFetcher fetcher; private boolean assumeValidRestReferences; + private Locale locale; private class AsteriskFilter implements FilenameFilter { String dir; @@ -1269,6 +1272,7 @@ public class ValidationEngine implements IValidatorResourceFetcher { validator.setNoInvariantChecks(isNoInvariantChecks()); validator.setValidationLanguage(language); validator.setAssumeValidRestReferences(assumeValidRestReferences); + validator.getContext().setLocale(locale); validator.setFetcher(this); return validator; } @@ -1592,6 +1596,11 @@ public class ValidationEngine implements IValidatorResourceFetcher { return false; } + @Override + public void setLocale(Locale locale) { + this.locale = locale; + } + public void handleOutput(Resource r, String output, String version) throws Exception { if (output.startsWith("http://") || output.startsWith("http://")) { ByteArrayOutputStream bs = new ByteArrayOutputStream(); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java index 408ed8739..e69c96e96 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java @@ -55,6 +55,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -195,6 +196,8 @@ public class Validator { System.out.println(" Produce additional information about the loading/validation process"); System.out.println("-recurse"); System.out.println(" Look in subfolders when -ig refers to a folder"); + System.out.println("-locale"); + System.out.println(" Specifies the locale/language of the validation result messages (eg.: de-DE"); System.out.println("-sct"); System.out.println(" Specify the edition of SNOMED CT to use. Valid Choices:"); System.out.println(" intl | us | uk | au | nl | ca | se | dk | es"); @@ -399,6 +402,7 @@ public class Validator { boolean anyExtensionsAllowed = true; boolean hintAboutNonMustSupport = false; boolean recursive = false; + Locale locale = null; List profiles = new ArrayList(); EngineMode mode = EngineMode.VALIDATION; String output = null; @@ -477,6 +481,12 @@ public class Validator { throw new Error("Snomed edition '"+s+"' not known"); } else if (args[i].equals("-recurse")) { recursive = true; + } else if (args[i].equals("-locale")) { + if (i+1 == args.length) { + throw new Error("Specified -locale without indicating locale"); + } else { + locale = new Locale(args[++i]); + } } else if (args[i].equals("-strictExtensions")) { anyExtensionsAllowed = false; } else if (args[i].equals("-hintAboutNonMustSupport")) { @@ -585,6 +595,7 @@ public class Validator { validator.setHintAboutNonMustSupport(hintAboutNonMustSupport); validator.setAnyExtensionsAllowed(anyExtensionsAllowed); validator.setLanguage(lang); + validator.setLocale(locale); validator.setSnomedExtension(snomedCT); validator.setAssumeValidRestReferences(assumeValidRestReferences); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 2cff601ae..f6ccb25f0 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -126,6 +126,7 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext; import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.I18nConstants; import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack; import org.hl7.fhir.validation.XVerExtensionManager; @@ -141,7 +142,6 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.xhtml.NodeType; import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.validation.instance.utils.*; -import org.hl7.fhir.validation.utils.I18nConstants; import org.w3c.dom.Document; import com.google.gson.Gson; @@ -197,17 +197,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public FunctionDetails resolveFunction(String functionName) { - throw new Error(formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESRESOLVEFUNCTION_, functionName)); + throw new Error(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESRESOLVEFUNCTION_, functionName)); } @Override public TypeDetails checkFunction(Object appContext, String functionName, List parameters) throws PathEngineException { - throw new Error(formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESCHECKFUNCTION)); + throw new Error(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESCHECKFUNCTION)); } @Override public List executeFunction(Object appContext, String functionName, List> parameters) { - throw new Error(formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESEXECUTEFUNCTION)); + throw new Error(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESEXECUTEFUNCTION)); } @Override @@ -240,7 +240,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat throw new FHIRException(e); } else - throw new Error(formatMessage(I18nConstants.NOT_DONE_YET__RESOLVE__LOCALLY_2, url)); + throw new Error(context.formatMessage(I18nConstants.NOT_DONE_YET__RESOLVE__LOCALLY_2, url)); } @@ -269,7 +269,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ValidatorHostContext ctxt = (ValidatorHostContext) appContext; StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); if (sd == null) { - throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_, url)); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_, url)); } InstanceValidator self = InstanceValidator.this; List valerrors = new ArrayList(); @@ -285,10 +285,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (e.isResource()) { self.validateResource(new ValidatorHostContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(e)); } else { - throw new FHIRException(formatMessage(I18nConstants.NOT_SUPPORTED_YET)); + throw new FHIRException(context.formatMessage(I18nConstants.NOT_SUPPORTED_YET)); } } else - throw new NotImplementedException(formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESCONFORMSTOPROFILE_WHEN_ITEM_IS_NOT_AN_ELEMENT)); + throw new NotImplementedException(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESCONFORMSTOPROFILE_WHEN_ITEM_IS_NOT_AN_ELEMENT)); boolean ok = true; List record = new ArrayList<>(); for (ValidationMessage v : valerrors) { @@ -312,7 +312,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (r instanceof ValueSet) return (ValueSet) r; else - throw new FHIRException(formatMessage(I18nConstants.REFERENCE__REFERS_TO_A__NOT_A_VALUESET, url, r.fhirType())); + throw new FHIRException(context.formatMessage(I18nConstants.REFERENCE__REFERS_TO_A__NOT_A_VALUESET, url, r.fhirType())); } } return null; @@ -515,7 +515,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private StructureDefinition getSpecifiedProfile(String profile) { StructureDefinition sd = context.fetchResource(StructureDefinition.class, profile); if (sd == null) { - throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_LOCATE_THE_PROFILE__IN_ORDER_TO_VALIDATE_AGAINST_IT, profile)); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_LOCATE_THE_PROFILE__IN_ORDER_TO_VALIDATE_AGAINST_IT, profile)); } return sd; } @@ -1568,7 +1568,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = true; } } else { - throw new Error(formatMessage(I18nConstants.UNRECOGNISED_EXTENSION_CONTEXT_, ctxt.getTypeElement().asStringValue())); + throw new Error(context.formatMessage(I18nConstants.UNRECOGNISED_EXTENSION_CONTEXT_, ctxt.getTypeElement().asStringValue())); } } if (!ok) { @@ -2095,7 +2095,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (we == null) { if (fetcher == null) { if (!refType.equals("contained")) - throw new FHIRException(formatMessage(I18nConstants.RESOURCE_RESOLUTION_SERVICES_NOT_PROVIDED)); + throw new FHIRException(context.formatMessage(I18nConstants.RESOURCE_RESOLUTION_SERVICES_NOT_PROVIDED)); } else { Element ext = null; if (fetchCache.containsKey(ref)) { @@ -2190,7 +2190,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!isShowMessagesFromReferences()) { rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, areAllBaseProfiles(profiles), I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile())); for (StructureDefinition sd : badProfiles.keySet()) { - slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, "Details for " + ref + " matching against Profile" + sd.getUrl(), errorSummaryForSlicingAsHtml(badProfiles.get(sd))); + slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, + context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()), errorSummaryForSlicingAsHtml(badProfiles.get(sd))); } } else { rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() == 1, I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile())); @@ -2206,7 +2207,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!isShowMessagesFromReferences()) { warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet())); for (StructureDefinition sd : badProfiles.keySet()) { - slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, "Details for " + ref + " matching against Profile" + sd.getUrl(), errorSummaryForSlicingAsHtml(badProfiles.get(sd))); + slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()), errorSummaryForSlicingAsHtml(badProfiles.get(sd))); } } else { warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet())); @@ -2480,7 +2481,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat String id = p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT) ? p.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT) : null; StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue()); if (sd == null) - throw new DefinitionException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE_, p)); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE_, p)); profile = sd; if (id == null) element = sd.getSnapshot().getElementFirstRep(); @@ -2491,7 +2492,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat element = t; } if (element == null) - throw new DefinitionException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_ELEMENT__IN_PROFILE_, id, p)); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_ELEMENT__IN_PROFILE_, id, p)); } expr = fpe.parse(fixExpr(discriminator)); t2 = System.nanoTime(); @@ -2642,20 +2643,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (focus.fhirType().equals("Reference") && d.equals("reference")) { String url = focus.getChildValue("reference"); if (Utilities.noString(url)) - throw new FHIRException(formatMessage(I18nConstants.NO_REFERENCE_RESOLVING_DISCRIMINATOR__FROM_, discriminator, element.getProperty().getName())); + throw new FHIRException(context.formatMessage(I18nConstants.NO_REFERENCE_RESOLVING_DISCRIMINATOR__FROM_, discriminator, element.getProperty().getName())); // Note that we use the passed in stack here. This might be a problem if the discriminator is deep enough? Element target = resolve(appContext, url, stack, errors, p); if (target == null) - throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCE__AT__RESOLVING_DISCRIMINATOR__FROM_, url, d, discriminator, element.getProperty().getName())); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCE__AT__RESOLVING_DISCRIMINATOR__FROM_, url, d, discriminator, element.getProperty().getName())); focus = target; } else if (d.equals("value") && focus.isPrimitive()) { return focus; } else { List children = focus.getChildren(d); if (children.isEmpty()) - throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_FIND__RESOLVING_DISCRIMINATOR__FROM_, d, discriminator, element.getProperty().getName())); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_FIND__RESOLVING_DISCRIMINATOR__FROM_, d, discriminator, element.getProperty().getName())); if (children.size() > 1) - throw new FHIRException(formatMessage(I18nConstants.FOUND__ITEMS_FOR__RESOLVING_DISCRIMINATOR__FROM_, Integer.toString(children.size()), d, discriminator, element.getProperty().getName())); + throw new FHIRException(context.formatMessage(I18nConstants.FOUND__ITEMS_FOR__RESOLVING_DISCRIMINATOR__FROM_, Integer.toString(children.size()), d, discriminator, element.getProperty().getName())); focus = children.get(0); p = p + "." + d; } @@ -3080,23 +3081,23 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat discriminator = discriminator.substring(0, discriminator.indexOf('[')); type = criteriaElement.getType().get(0).getWorkingCode(); } else if (criteriaElement.getType().size() > 1) { - throw new DefinitionException(formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_MULTIPLE_TYPES_, discriminator, ed.getId(), profile.getUrl(), criteriaElement.typeSummary())); + throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_MULTIPLE_TYPES_, discriminator, ed.getId(), profile.getUrl(), criteriaElement.typeSummary())); } else - throw new DefinitionException(formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES, discriminator, ed.getId(), profile.getUrl())); + throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES, discriminator, ed.getId(), profile.getUrl())); if (discriminator.isEmpty()) expression.append(" and $this is " + type); else expression.append(" and " + discriminator + " is " + type); } else if (s.getType() == DiscriminatorType.PROFILE) { if (criteriaElement.getType().size() == 0) { - throw new DefinitionException(formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl())); + throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl())); } if (criteriaElement.getType().size() != 1) { - throw new DefinitionException(formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_ONLY_ONE_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl())); + throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_ONLY_ONE_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl())); } List list = discriminator.endsWith(".resolve()") || discriminator.equals("resolve()") ? criteriaElement.getType().get(0).getTargetProfile() : criteriaElement.getType().get(0).getProfile(); if (list.size() == 0) { - throw new DefinitionException(formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE_WITH_A_PROFILE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl())); + throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE_WITH_A_PROFILE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl())); } else if (list.size() > 1) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(" or "); for (CanonicalType c : list) { @@ -3112,7 +3113,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat else if (criteriaElement.hasMax() && criteriaElement.getMax().equals("0")) expression.append(" and (" + discriminator + ".exists().not())"); else - throw new FHIRException(formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_ELEMENT_EXISTENCE_BUT_SLICE__NEITHER_SETS_MIN1_OR_MAX0, discriminator, ed.getId())); + throw new FHIRException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_ELEMENT_EXISTENCE_BUT_SLICE__NEITHER_SETS_MIN1_OR_MAX0, discriminator, ed.getId())); } else if (criteriaElement.hasFixed()) { buildFixedExpression(ed, expression, discriminator, criteriaElement); } else if (criteriaElement.hasPattern()) { @@ -3130,15 +3131,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } if (!anyFound) { if (slicer.getSlicing().getDiscriminator().size() > 1) - throw new DefinitionException(formatMessage(I18nConstants.COULD_NOT_MATCH_ANY_DISCRIMINATORS__FOR_SLICE__IN_PROFILE___NONE_OF_THE_DISCRIMINATOR__HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators)); + throw new DefinitionException(context.formatMessage(I18nConstants.COULD_NOT_MATCH_ANY_DISCRIMINATORS__FOR_SLICE__IN_PROFILE___NONE_OF_THE_DISCRIMINATOR__HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators)); else - throw new DefinitionException(formatMessage(I18nConstants.COULD_NOT_MATCH_DISCRIMINATOR__FOR_SLICE__IN_PROFILE___THE_DISCRIMINATOR__DOES_NOT_HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators)); + throw new DefinitionException(context.formatMessage(I18nConstants.COULD_NOT_MATCH_DISCRIMINATOR__FOR_SLICE__IN_PROFILE___THE_DISCRIMINATOR__DOES_NOT_HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators)); } try { n = fpe.parse(fixExpr(expression.toString())); } catch (FHIRLexerException e) { - throw new FHIRException(formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, expression, profile.getUrl(), path, e.getMessage())); + throw new FHIRException(context.formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, expression, profile.getUrl(), path, e.getMessage())); } fpeTime = fpeTime + (System.nanoTime() - t); ed.setUserData("slice.expression.cache", n); @@ -3147,10 +3148,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ValidatorHostContext shc = hostContext.forSlicing(); boolean pass = evaluateSlicingExpression(shc, element, path, profile, n); if (!pass) { - slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, "Does not match slice'" + ed.getSliceName(), "discriminator = " + Utilities.escapeXml(n.toString())); + slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, (context.formatMessage(I18nConstants.DOES_NOT_MATCH_SLICE_, ed.getSliceName())), "discriminator = " + Utilities.escapeXml(n.toString())); for (String url : shc.getSliceRecords().keySet()) { - slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, "Details for " + stack.getLiteralPath() + " against profile " + url, - "Profile " + url + " does not match for " + stack.getLiteralPath() + " because of the following profile issues: " + errorSummaryForSlicingAsHtml(shc.getSliceRecords().get(url))); + slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, + context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, stack.getLiteralPath(), url), + context.formatMessage(I18nConstants.PROFILE__DOES_NOT_MATCH_FOR__BECAUSE_OF_THE_FOLLOWING_PROFILE_ISSUES__, + url, + stack.getLiteralPath(), errorSummaryForSlicingAsHtml(shc.getSliceRecords().get(url)))); } } return pass; @@ -3166,7 +3170,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat msg = fpe.forLog(); } catch (Exception ex) { ex.printStackTrace(); - throw new FHIRException(formatMessage(I18nConstants.PROBLEM_EVALUATING_SLICING_EXPRESSION_FOR_ELEMENT_IN_PROFILE__PATH__FHIRPATH___, profile.getUrl(), path, n, ex.getMessage())); + throw new FHIRException(context.formatMessage(I18nConstants.PROBLEM_EVALUATING_SLICING_EXPRESSION_FOR_ELEMENT_IN_PROFILE__PATH__FHIRPATH___, profile.getUrl(), path, n, ex.getMessage())); } return ok; } @@ -3185,14 +3189,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat Identifier ii = (Identifier) pattern; expression.append(" and "); buildIdentifierExpression(ed, expression, discriminator, ii); - } else - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_FIXED_PATTERN_TYPE_FOR_DISCRIMINATOR_FOR_SLICE__, discriminator, ed.getId(), pattern.getClass().getName())); + } else { + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_FIXED_PATTERN_TYPE_FOR_DISCRIMINATOR_FOR_SLICE__, discriminator, ed.getId(), pattern.getClass().getName())); + } } private void buildIdentifierExpression(ElementDefinition ed, StringBuilder expression, String discriminator, Identifier ii) throws DefinitionException { if (ii.hasExtension()) - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); boolean first = true; expression.append(discriminator + ".where("); if (ii.hasSystem()) { @@ -3226,15 +3231,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private void buildCodeableConceptExpression(ElementDefinition ed, StringBuilder expression, String discriminator, CodeableConcept cc) throws DefinitionException { if (cc.hasText()) - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__USING_TEXT__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__USING_TEXT__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); if (!cc.hasCoding()) - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__MUST_HAVE_AT_LEAST_ONE_CODING__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__MUST_HAVE_AT_LEAST_ONE_CODING__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); if (cc.hasExtension()) - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); boolean firstCoding = true; for (Coding c : cc.getCoding()) { if (c.hasExtension()) - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); if (firstCoding) firstCoding = false; else expression.append(" and "); expression.append(discriminator + ".coding.where("); @@ -3265,7 +3270,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private void buildCodingExpression(ElementDefinition ed, StringBuilder expression, String discriminator, Coding c) throws DefinitionException { if (c.hasExtension()) - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_CODEABLECONCEPT_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId())); expression.append(discriminator + ".where("); boolean first = true; if (c.hasSystem()) { @@ -3321,7 +3326,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (fixed instanceof BooleanType) { expression.append(((BooleanType) fixed).asStringValue()); } else - throw new DefinitionException(formatMessage(I18nConstants.UNSUPPORTED_FIXED_VALUE_TYPE_FOR_DISCRIMINATOR_FOR_SLICE__, discriminator, ed.getId(), fixed.getClass().getName())); + throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_FIXED_VALUE_TYPE_FOR_DISCRIMINATOR_FOR_SLICE__, discriminator, ed.getId(), fixed.getClass().getName())); expression.append(" in " + discriminator + ")"); } } @@ -3335,6 +3340,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } startInner(hostContext, errors, resource, element, defn, stack, hostContext.isCheckSpecials()); + List res = new ArrayList<>(); Element meta = element.getNamedChild("meta"); if (meta != null) { List profiles = new ArrayList(); @@ -3682,7 +3688,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat byte[] json = bs.toByteArray(); switch (v) { case DSTU1: - throw new FHIRException(formatMessage(I18nConstants.UNSUPPORTED_VERSION_R1)); + throw new FHIRException(context.formatMessage(I18nConstants.UNSUPPORTED_VERSION_R1)); case DSTU2: org.hl7.fhir.dstu2.model.Resource r2 = new org.hl7.fhir.dstu2.formats.JsonParser().parse(json); Resource r5 = VersionConvertor_10_50.convertResource(r2); @@ -4624,7 +4630,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat else dt = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + actualType); if (dt == null) - throw new DefinitionException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_ACTUAL_TYPE_, actualType)); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_ACTUAL_TYPE_, actualType)); trackUsage(dt, hostContext, element); childDefinitions = profileUtilities.getChildMap(dt, dt.getSnapshot().getElement().get(0)); @@ -4982,7 +4988,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat String errorContext = "profile " + profile.getUrl(); if (!resource.getChildValue("id").isEmpty()) errorContext += "; instance " + resource.getChildValue("id"); - throw new DefinitionException(formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext)); + throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext)); } slicer = ed; process = false; @@ -5007,10 +5013,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (ei.additionalSlice && ei.definition != null) { if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPENATEND) && true /* TODO: replace "true" with condition to check that this element is at "end" */) { - slicingHint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.getPath(), false, "This element does not match any known slice" + (profile == null ? "" : " defined in the profile " + profile.getUrl()), - "This element does not match any known slice" + (profile == null ? "" : " defined in the profile " + profile.getUrl() + ": " + errorSummaryForSlicingAsHtml(ei.sliceInfo))); + slicingHint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.getPath(), false, + context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, + profile == null ? "" : " defined in the profile " + profile.getUrl()), + context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, profile == null ? "" : I18nConstants.DEFINED_IN_THE_PROFILE + profile.getUrl()) + errorSummaryForSlicingAsHtml(ei.sliceInfo)); } else if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.CLOSED)) { - rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOTSLICE, (profile == null ? "" : " defined in the profile " + profile.getUrl() + " and slicing is CLOSED: " + errorSummaryForSlicing(ei.sliceInfo))); + rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOTSLICE, (profile == null ? "" : " defined in the profile " + profile.getUrl()), errorSummaryForSlicing(ei.sliceInfo)); } } else { // Don't raise this if we're in an abstract profile, like Resource @@ -5106,7 +5114,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (tail.equals(t.getId())) return t; } - throw new DefinitionException(formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT_WITH_ID_, tail)); + throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT_WITH_ID_, tail)); } private IdStatus idStatusForEntry(Element ep, ElementInfo ei) { @@ -5193,7 +5201,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { n = fpe.parse(fixExpr(inv.getExpression())); } catch (FHIRLexerException e) { - throw new FHIRException(formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, inv.getExpression(), profile.getUrl(), path, e.getMessage())); + throw new FHIRException(context.formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, inv.getExpression(), profile.getUrl(), path, e.getMessage())); } fpeTime = fpeTime + (System.nanoTime() - t); inv.setUserData("validator.expression.cache", n); @@ -5332,9 +5340,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat checkFixedValue(msgs, "{virtual}", value, criteria.getFixed(), profile.getUrl(), "value", null); return msgs.size() == 0; } else if (criteria.hasBinding() && criteria.getBinding().getStrength() == BindingStrength.REQUIRED && criteria.getBinding().hasValueSet()) { - throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SLICE_MATCHING__SLICE_MATCHING_BY_VALUE_SET_NOT_DONE)); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SLICE_MATCHING__SLICE_MATCHING_BY_VALUE_SET_NOT_DONE)); } else { - throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SLICE_MATCHING__NO_FIXED_VALUE_OR_REQUIRED_VALUE_SET)); + throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_SLICE_MATCHING__NO_FIXED_VALUE_OR_REQUIRED_VALUE_SET)); } } @@ -5593,6 +5601,4 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat public void setDebug(boolean debug) { this.debug = debug; } - - } diff --git a/org.hl7.fhir.validation/src/main/resources/Messages.properties b/org.hl7.fhir.validation/src/main/resources/Messages.properties index 5a4646466..000d99036 100644 --- a/org.hl7.fhir.validation/src/main/resources/Messages.properties +++ b/org.hl7.fhir.validation/src/main/resources/Messages.properties @@ -212,7 +212,7 @@ Validation_VAL_Profile_NoMatch = Unable to find matching profile among choices: Validation_VAL_Profile_NoSnapshot = StructureDefinition has no snapshot - validation is against the snapshot, so it must be provided Validation_VAL_Profile_NoType = The type of element {0} is not known, which is illegal. Valid types at this point are {1} Validation_VAL_Profile_NotAllowed = This element is not allowed by the profile {0} -Validation_VAL_Profile_NotSlice = This element does not match any known slice {0} +Validation_VAL_Profile_NotSlice = This element does not match any known slice {0} and slicing is CLOSED: {1} Validation_VAL_Profile_OutOfOrder = As specified by profile {0}, Element "{1}" is out of order Validation_VAL_Profile_SliceOrder = As specified by profile {0}, Element "{1}" is out of order in ordered slice Validation_VAL_Profile_Unknown = Profile reference "{0}" could not be resolved, so has not been checked @@ -265,3 +265,166 @@ Not_done_yet__resolve__locally_2 = Not done yet - resolve {0} locally (2) Not_done_yet_ValidatorHostServicesexecuteFunction = Not done yet (ValidatorHostServices.executeFunction) Not_done_yet_ValidatorHostServicescheckFunction = Not done yet (ValidatorHostServices.checkFunction) Not_done_yet_ValidatorHostServicesresolveFunction_ = Not done yet (ValidatorHostServices.resolveFunction): {0} +Unable_to_find_base_definition_for_logical_model__from_ = Unable to find base definition for logical model: {0} from {1} +Same_id_on_multiple_elements__in_ = Same id ''{0}''on multiple elements {1}/{2} in {3} +No_path_on_element_Definition__in_ = No path on element Definition {0} in {1} +needs_a_snapshot = needs a snapshot +not_the_right_kind_of_structure_to_generate_schematrons_for = not the right kind of structure to generate schematrons for +Not_handled_yet_sortElements_ = Not handled yet (sortElements: {0}:{1}) +Unable_to_resolve_profile__in_element_ = Unable to resolve profile {0} in element {1} +Cant_have_children_on_an_element_with_a_polymorphic_type__you_must_slice_and_constrain_the_types_first_sortElements_ = Can''t have children on an element with a polymorphic type - you must slice and constrain the types first (sortElements: {0}:{1}) +Unable_to_find_profile__at_ = Unable to find profile ''{0}'' at {1} +Unhandled_situation_resource_is_profiled_to_more_than_one_option__cannot_sort_profile = Unhandled situation: resource is profiled to more than one option - cannot sort profile +Internal_recursion_detection_find_loop_path_recursion____check_paths_are_valid_for_path_ = Internal recursion detection: find() loop path recursion > {0} - check paths are valid (for path {1}/{2}) +Internal_error___type_not_known_ = Internal error - type not known {0} +Unable_to_find_element_ = Unable to find element {0} +Error_generating_table_for_profile__ = Error generating table for profile {0}: {1} +StructureDefinition__at__illegal_constrained_type__from__in_ = StructureDefinition {0} at {1}: illegal constrained type {2} from {3} in {4} +Error_at__The_target_profile__is_not__valid_constraint_on_the_base_ = Error at {0}#{1}: The target profile {2} is not valid constraint on the base ({3}) +Error_in_profile__at__Base_isSummary___derived_isSummary__ = Error in profile {0} at {1}: Base isSummary = {2}, derived isSummary = {3} +StructureDefinition__at__illegal_attempt_to_change_a_binding_from__to_ = StructureDefinition {0} at {1}: illegal attempt to change a binding from {2} to {3} +Unexpected_condition_in_differential_typeslicetypelistsize__1_at_ = Unexpected condition in differential: type-slice.type-list.size() != 1 at {0}/{1} +Unexpected_condition_in_differential_typeslicetypelistsize__10_and_implicit_slice_name_does_not_contain_a_valid_type__at_ = Unexpected condition in differential: type-slice.type-list.size() == 10 and implicit slice name does not contain a valid type (''{0}''?) at {1}/{2} +Attempt_to_use_a_snapshot_on_profile__as__before_it_is_generated = Attempt to use a snapshot on profile ''{0}'' as {1} before it is generated +null_min = null min +_has_children__for_type__in_profile__but_cant_find_type = {0} has children ({1}) for type {2} in profile {3}, but can''t find type +_has_children__and_multiple_types__in_profile_ = {0} has children ({1}) and multiple types ({2}) in profile {3} +Adding_wrong_path = Adding wrong path +Named_items_are_out_of_order_in_the_slice=Named items are out of order in the slice +The_base_snapshot_marks_a_slicing_as_closed_but_the_differential_tries_to_extend_it_in__at__ = The base snapshot marks a slicing as closed, but the differential tries to extend it in {0} at {1} ({2}) +Not_done_yet = Not done yet +Unknown_type__at_ = Unknown type {0} at {1} +Differential_walks_into____but_the_base_does_not_and_there_is_not_a_single_fixed_type_The_type_is__This_is_not_handled_yet = Differential walks into ''{0} (@ {1})'', but the base does not, and there is not a single fixed type. The type is {2}. This is not handled yet +Slicing_rules_on_differential__do_not_match_those_on_base___rule___ = Slicing rules on differential ({0}) do not match those on base ({1}) - rule @ {2} ({3}) +Slicing_rules_on_differential__do_not_match_those_on_base___disciminator___ = Slicing rules on differential ({0}) do not match those on base ({1}) - disciminator @ {2} ({3}) +Slicing_rules_on_differential__do_not_match_those_on_base___order___ = Slicing rules on differential ({0}) do not match those on base ({1}) - order @ {2} ({3}) +not_done_yet__slicing__types__ = not done yet - slicing / types @ {0} +Invalid_slicing__there_is_more_than_one_type_slice_at__but_one_of_them__has_min__1_so_the_other_slices_cannot_exist=Invalid slicing: there is more than one type slice at {0}, but one of them ({1}) has min = 1, so the other slices cannot exist +Did_not_find_type_root_ = Did not find type root: {0} +Error_at_path__Slice_for_type__has_wrong_type_ = Error at path {0}: Slice for type ''{1}'' has wrong type ''{2}'' +Error_at_path__Slice_for_type__has_more_than_one_type_ = Error at path {0}: Slice for type '{1}' has more than one type '{2}' +Error_at_path__Slice_name_must_be__but_is_ = Error at path {0}: Slice name must be ''{1}'' but is ''{2}'' +Error_at_path__in__Type_slicing_with_slicingdiscriminatorpath__this = Error at path {0} in {1}: Type slicing with slicing.discriminator.path != ''$this'' +Error_at_path__in__Type_slicing_with_slicingdiscriminatortype__type = Error at path {0} in {1}: Type slicing with slicing.discriminator.type != ''type'' +Error_at_path__in__Type_slicing_with_slicingdiscriminatorcount__1 = Error at path {0} in {1}: Type slicing with slicing.discriminator.count() > 1 +Error_at_path__in__Type_slicing_with_slicingordered__true = Error at path {0} in {1}: Type slicing with slicing.ordered = true +Adding_wrong_path_in_profile___vs_ = Adding wrong path in profile {0}: {1} vs {2} +_has_no_children__and_no_types_in_profile_ = {0} has no children ({1}) and no types in profile {2} +not_done_yet = not done yet +Did_not_find_single_slice_ = Did not find single slice: {0} +Differential_does_not_have_a_slice__b_of_____in_profile_ = Differential does not have a slice: {0}/ (b:{1} of {2} / {3}/ {4}) in profile {5} +Attempt_to_a_slice_an_element_that_does_not_repeat__from__in_ = Attempt to a slice an element that does not repeat: {0}/{1} from {2} in {3} +Unable_to_resolve_reference_to_ = Unable to resolve reference to {0} +Unable_to_find_element__in_ = Unable to find element {0} in {1} +Unable_to_find_base__for_ = Unable to find base {0} for {1} +Adding_wrong_path__outcomegetPath___resultPathBase__ = Adding wrong path - outcome.getPath() = {0}, resultPathBase = {1} +Illegal_path__in_differential_in__illegal_characters_ = Illegal path ''{0}'' in differential in {1}: illegal characters [] +Illegal_path__in_differential_in__illegal_character_ = Illegal path ''{0}'' in differential in {1}: illegal character ''{2}'' +Illegal_path__in_differential_in__no_unicode_whitespace = Illegal path ''{0}'' in differential in {1}: no unicode whitespace +Illegal_path__in_differential_in__name_portion_exceeds_64_chars_in_length = Illegal path ''{0}'' in differential in {1}: name portion exceeds 64 chars in length +Illegal_path__in_differential_in__name_portion_mising_ = Illegal path ''{0}'' in differential in {1}: name portion missing (''..'') +Illegal_path__in_differential_in__must_start_with_ = Illegal path ''{0}'' in differential in {1}: must start with {2}.{3} +No_path_value_on_element_in_differential_in_ = No path value on element in differential in {0} +No_path_on_element_in_differential_in_ = No path on element in differential in {0} +Unxpected_internal_condition__no_source_on_diff_element = Unxpected internal condition - no source on diff element +type_on_first_snapshot_element_for__in__from_ = type on first snapshot element for {0} in {1} from {2} +type_on_first_differential_element = type on first differential element! +Circular_snapshot_references_detected_cannot_generate_snapshot_stack__ = Circular snapshot references detected; cannot generate snapshot (stack = {0}) +Base__Derived_profiles_have_different_types____vs___ = Base & Derived profiles have different types ({0} = {1} vs {2} = {3}) +Derived_profile__has_no_derivation_value_and_so_cant_be_processed = Derived profile {0} has no derivation value and so can''t be processed +Derived_profile__has_no_type = Derived profile {0} has no type +Base_profile__has_no_type = Base profile {0} has no type +no_derived_structure_provided = no derived structure provided +no_base_profile_provided = no base profile provided +element_id__null__on_ = element id = null: {0} on {1} +element__null_ = element = null: {0} +getSliceList_should_only_be_called_when_the_element_has_slicing = getSliceList should only be called when the element has slicing +Unable_to_resolve_name_reference__at_path_ = Unable to resolve name reference {0} at path {1} +Details_for__matching_against_Profile_ = Details for {0} matching against Profile{1} +Does_not_match_slice_ = Does not match slice "{0}" +Profile__does_not_match_for__because_of_the_following_profile_issues__ = Profile {0} does not match for {1} because of the following profile issues: {2} +This_element_does_not_match_any_known_slice_ = This element does not match any known slice{0} +defined_in_the_profile = defined in the profile +This_does_not_appear_to_be_a_FHIR_resource_unknown_name_ = This does not appear to be a FHIR resource (unknown name "{0}") +This_cannot_be_parsed_as_a_FHIR_object_no_name = This cannot be parsed as a FHIR object (no name) +This_does_not_appear_to_be_a_FHIR_resource_unknown_namespacename_ = This does not appear to be a FHIR resource (unknown namespace/name "{0}::{1}") +This__cannot_be_parsed_as_a_FHIR_object_no_namespace = This "{0}2 cannot be parsed as a FHIR object (no namespace) +Unable_to_find_resourceType_property = Unable to find resourceType property +Error_parsing_JSON_the_primitive_value_must_be_a_string = Error parsing JSON: the primitive value must be a string +Error_parsing_JSON_the_primitive_value_must_be_a_number = Error parsing JSON: the primitive value must be a number +Error_parsing_JSON_the_primitive_value_must_be_a_boolean = Error parsing JSON: the primitive value must be a boolean +Error_parsing_XHTML_ = Error parsing XHTML: {0} +This_property_must_be_an_object_not_ = This property must be an object, not {0} +This_property_must_be_an_simple_value_not_ = This property must be an simple value, not {0} +This_property_must_be__not_ = This property must be {0}, not {1} +This_property_must_be_an_Array_not_ = This property must be an Array, not {0} +Unrecognised_property_ = Unrecognised property ''@{0}'' +Object_must_have_some_content = Object must have some content +Error_parsing_JSON_ = Error parsing JSON: {0} +Node_type__is_not_allowed = Node type {0} is not allowed +CDATA_is_not_allowed = CDATA is not allowed +Undefined_element_ = Undefined element ''{0}'' +Undefined_attribute__on__for_type__properties__ = Undefined attribute ''@{0}'' on {1} for type {2} (properties = {3}) +Text_should_not_be_present = Text should not be present +Wrong_namespace__expected_ = Wrong namespace - expected ''{0}'' +Element_must_have_some_content = Element must have some content +No_processing_instructions_allowed_in_resources = No processing instructions allowed in resources +Unknown_resource_type_missing_rdfstype = Unknown resource type (missing rdfs:type) +reference_to__cannot_be_resolved = reference to {0} cannot be resolved +This_property_must_be_a_URI_or_bnode_not_a_ = This property must be a URI or bnode, not a {0} +This_property_must_be_a_Literal_not_a_ = This property must be a Literal, not a {0} +Unrecognised_predicate_ = Unrecognised predicate ''{0}'' +Error_parsing_Turtle_ = Error parsing Turtle: {0} +Unexpected_datatype_for_rdfstype = Unexpected datatype for rdfs:type +Attempt_to_replace_element_name_for_a_nonchoice_type=Attempt to replace element name for a non-choice type +Wrong_type_for_resource = Wrong type for resource +Contained_resource_does_not_appear_to_be_a_FHIR_resource_unknown_name_ = Contained resource does not appear to be a FHIR resource (unknown name ''{0}'') +Unknown_Date_format_ = Unknown Date format ''{0}'' +Unknown_Data_format_ = Unknown Data format ''{0}'' +No_type_found_on_ = No type found on ''{0}'' +error_writing_number__to_JSON = error writing number ''{0}'' to JSON +Unable_to_process_request_for_resource_for___ = Unable to process request for resource for {0} / {1} +Resource_type_mismatch_for___ = Resource type mismatch for {0} / {1} +not_done_yet_cant_fetch_ = not done yet: can''t fetch {0} +Attempt_to_use_Terminology_server_when_no_Terminology_server_is_available = Attempt to use Terminology server when no Terminology server is available +No_ExpansionProfile_provided = No ExpansionProfile provided +Can_only_specify_profile_in_the_context = Can only specify profile in the context +no_url_in_expand_value_set_2 = no url in expand value set 2 +no_url_in_expand_value_set = no url in expand value set +no_value_set = no value set +No_Parameters_provided_to_expandVS = No Parameters provided to expandVS +No_Expansion_Parameters_provided = No Expansion Parameters provided +Unable_to_resolve_value_Set_ = Unable to resolve value Set {0} +Delimited_versions_have_exact_match_for_delimiter____vs_ = Delimited versions have exact match for delimiter ''{0}'' : {1} vs {2} +Duplicate_Resource_ = Duplicate Resource {0} +Error_expanding_ValueSet_running_without_terminology_services = Error expanding ValueSet: running without terminology services +Error_validating_code_running_without_terminology_services = Error validating code: running without terminology services +Unable_to_validate_code_without_using_server = Unable to validate code without using server +Profile___Error_generating_snapshot = Profile {0} ({1}). Error generating snapshot +Profile___element__Error_generating_snapshot_ = Profile {0} ({1}), element {2}. Error generating snapshot: {3} +Profile___base__could_not_be_resolved = Profile {0} ({1}) base {2} could not be resolved +Profile___has_no_base_and_no_snapshot = Profile {0} ({1}) has no base and no snapshot +No_validator_configured = No validator configured +Parser_Type__not_supported = Parser Type {0} not supported +Version_mismatch_The_context_has_version__loaded_and_the_new_content_being_loaded_is_version_ = Version mismatch. The context has version {0} loaded, and the new content being loaded is version {1} +Error_reading__from_package__ = Error reading {0} from package {1}#{2}: {3} +Error_parsing_ = Error parsing {0}:{1} +Unable_to_connect_to_terminology_server_Use_parameter_tx_na_tun_run_without_using_terminology_services_to_validate_LOINC_SNOMED_ICDX_etc_Error__ = Unable to connect to terminology server. Use parameter ''-tx n/a'' tun run without using terminology services to validate LOINC, SNOMED, ICD-X etc. Error = {0} +Display_Name_for__should_be_one_of__instead_of_ = Display Name for {0}#{1} should be one of ''{2}'' instead of ''{3}'' +Unknown_Code__in_ = Unknown Code {0} in {1} +Code_found_in_expansion_however_ = Code found in expansion, however: {0} +None_of_the_provided_codes_are_in_the_value_set_ = None of the provided codes are in the value set {0} +Coding_has_no_system__cannot_validate = Coding has no system - cannot validate +Unable_to_handle_system__concept_filter_with_op__ = Unable to handle system {0} concept filter with op = {1} +Unable_to_handle_system__filter_with_property__ = Unable to handle system {0} filter with property = {1} +Unable_to_resolve_system__value_set_has_include_with_no_system = Unable to resolve system - value set has include with no system +Unable_to_resolve_system__value_set_has_imports = Unable to resolve system - value set has imports +Unable_to_resolve_system__value_set_expansion_has_multiple_systems = Unable to resolve system - value set expansion has multiple systems +Unable_to_resolve_system__value_set_has_no_includes_or_expansion = Unable to resolve system - value set has no includes or expansion +Unable_to_resolve_system__value_set_has_excludes = Unable to resolve system - value set has excludes +Unable_to_resolve_system__no_value_set = Unable to resolve system - no value set +This_base_property_must_be_an_Array_not_a_ = This base property must be an Array, not a {0} +This_property_must_be_an_Array_not_a_ = This property must be an Array, not a {0} +documentmsg = (document) + + diff --git a/org.hl7.fhir.validation/src/main/resources/Messages_de.properties b/org.hl7.fhir.validation/src/main/resources/Messages_de.properties index eff94c7e3..bbfbb87fd 100644 --- a/org.hl7.fhir.validation/src/main/resources/Messages_de.properties +++ b/org.hl7.fhir.validation/src/main/resources/Messages_de.properties @@ -425,4 +425,6 @@ Unable_to_resolve_system__value_set_has_excludes=System nicht auflösbar - Value Unable_to_resolve_system__no_value_set=System nicht auflösbar - kein ValueSet This_base_property_must_be_an_Array_not_a_=Diese Basis Property muss ein Array sein, nicht ein {0} This_property_must_be_an_Array_not_a_=Diese Eigenschaft muss ein Array sein, nicht ein {0} -documentmsg = (document) \ No newline at end of file +documentmsg = (document) + + diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java index b89b5f5d5..dd95b31f8 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java @@ -426,6 +426,11 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour return !url.contains("example.org"); } + @Override + public void setLocale(Locale locale) { + //do nothing + } + @Override public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException { IResourceValidator val = TestingUtilities.context(version).newValidator();