mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-03-06 19:39:27 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
62fe79bff2
@ -34,6 +34,7 @@ import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
|
||||
|
||||
/**
|
||||
@ -78,7 +79,7 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
* Constructor
|
||||
*/
|
||||
public DecimalType(String theValue) {
|
||||
setValue(new BigDecimal(theValue));
|
||||
setValueAsString(theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -148,6 +149,14 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
setValue(new BigDecimal(theValue));
|
||||
}
|
||||
|
||||
public void setValueAsString(String theString) {
|
||||
if (StringUtils.isBlank(theString)) {
|
||||
setValue((BigDecimal) null);
|
||||
} else {
|
||||
setValue(new BigDecimal(theString));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalType copy() {
|
||||
return new DecimalType(getValue());
|
||||
|
@ -3,6 +3,11 @@ package org.hl7.fhir.dstu2.model;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class DecimalTypeNullTest {
|
||||
|
||||
@ -44,4 +49,27 @@ class DecimalTypeNullTest {
|
||||
DecimalType copyDecimal = (DecimalType) nullDecimal.typedCopy();
|
||||
Assertions.assertNull(copyDecimal.getValue());
|
||||
}
|
||||
|
||||
public static Stream<Arguments> provideEmptyOrNullStringsConstructor() {
|
||||
return Stream.of(
|
||||
Arguments.of((String)null),
|
||||
Arguments.of(""),
|
||||
Arguments.of(" ")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideEmptyOrNullStringsConstructor")
|
||||
void testNullValue(String theStringValue) {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
Assertions.assertNull(nullDecimal.getValue());
|
||||
Assertions.assertNull(nullDecimal.asStringValue());
|
||||
|
||||
DecimalType anotherNullDecimal = new DecimalType(theStringValue);
|
||||
Assertions.assertNull(anotherNullDecimal.getValue());
|
||||
Assertions.assertNull(anotherNullDecimal.asStringValue());
|
||||
|
||||
Assertions.assertTrue(nullDecimal.equalsDeep(anotherNullDecimal));
|
||||
Assertions.assertTrue(nullDecimal.equalsShallow(anotherNullDecimal));
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
@ -79,7 +80,7 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
* Constructor
|
||||
*/
|
||||
public DecimalType(String theValue) {
|
||||
setValue(new BigDecimal(theValue));
|
||||
setValueAsString(theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,6 +150,14 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
setValue(new BigDecimal(theValue));
|
||||
}
|
||||
|
||||
public void setValueAsString(String theString) {
|
||||
if (StringUtils.isBlank(theString)) {
|
||||
setValue((BigDecimal) null);
|
||||
} else {
|
||||
setValue(new BigDecimal(theString));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new value using a long
|
||||
*/
|
||||
|
@ -0,0 +1,75 @@
|
||||
package org.hl7.fhir.dstu2016may.model;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class DecimalTypeNullTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Test null value toString()")
|
||||
void testToString() {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
System.out.println("Value -> " + nullDecimal);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test null value equalsDeep()")
|
||||
void equalsDeep() {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
DecimalType validDecimal = new DecimalType("3.14");
|
||||
Assertions.assertFalse(nullDecimal.equalsDeep(validDecimal));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test null value equalsShallow()")
|
||||
void equalsShallow() {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
DecimalType validDecimal = new DecimalType("3.14");
|
||||
Assertions.assertFalse(nullDecimal.equalsShallow(validDecimal));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test null value copy()")
|
||||
void copy() {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
DecimalType copyDecimal = nullDecimal.copy();
|
||||
Assertions.assertNull(copyDecimal.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test null value typedCopy()")
|
||||
void typedCopy() {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
DecimalType copyDecimal = (DecimalType) nullDecimal.typedCopy();
|
||||
Assertions.assertNull(copyDecimal.getValue());
|
||||
}
|
||||
|
||||
public static Stream<Arguments> provideEmptyOrNullStringsConstructor() {
|
||||
return Stream.of(
|
||||
Arguments.of((String)null),
|
||||
Arguments.of(""),
|
||||
Arguments.of(" ")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideEmptyOrNullStringsConstructor")
|
||||
void testNullValue(String theStringValue) {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
Assertions.assertNull(nullDecimal.getValue());
|
||||
Assertions.assertNull(nullDecimal.asStringValue());
|
||||
|
||||
DecimalType anotherNullDecimal = new DecimalType(theStringValue);
|
||||
Assertions.assertNull(anotherNullDecimal.getValue());
|
||||
Assertions.assertNull(anotherNullDecimal.asStringValue());
|
||||
|
||||
Assertions.assertTrue(nullDecimal.equalsDeep(anotherNullDecimal));
|
||||
Assertions.assertTrue(nullDecimal.equalsShallow(anotherNullDecimal));
|
||||
}
|
||||
}
|
@ -1,33 +1,33 @@
|
||||
package org.hl7.fhir.dstu3.model;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
@ -81,7 +82,7 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
* Constructor
|
||||
*/
|
||||
public DecimalType(String theValue) {
|
||||
setValue(new BigDecimal(theValue));
|
||||
setValueAsString(theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -151,6 +152,14 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
setValue(BigDecimal.valueOf(theValue));
|
||||
}
|
||||
|
||||
public void setValueAsString(String theString) {
|
||||
if (StringUtils.isBlank(theString)) {
|
||||
setValue((BigDecimal) null);
|
||||
} else {
|
||||
setValue(new BigDecimal(theString));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new value using a long
|
||||
*/
|
||||
|
@ -3,6 +3,11 @@ package org.hl7.fhir.dstu3.model;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class DecimalTypeNullTest {
|
||||
|
||||
@ -44,4 +49,27 @@ class DecimalTypeNullTest {
|
||||
DecimalType copyDecimal = (DecimalType) nullDecimal.typedCopy();
|
||||
Assertions.assertNull(copyDecimal.getValue());
|
||||
}
|
||||
|
||||
public static Stream<Arguments> provideEmptyOrNullStringsConstructor() {
|
||||
return Stream.of(
|
||||
Arguments.of((String)null),
|
||||
Arguments.of(""),
|
||||
Arguments.of(" ")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideEmptyOrNullStringsConstructor")
|
||||
void testNullValue(String theStringValue) {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
Assertions.assertNull(nullDecimal.getValue());
|
||||
Assertions.assertNull(nullDecimal.asStringValue());
|
||||
|
||||
DecimalType anotherNullDecimal = new DecimalType(theStringValue);
|
||||
Assertions.assertNull(anotherNullDecimal.getValue());
|
||||
Assertions.assertNull(anotherNullDecimal.asStringValue());
|
||||
|
||||
Assertions.assertTrue(nullDecimal.equalsDeep(anotherNullDecimal));
|
||||
Assertions.assertTrue(nullDecimal.equalsShallow(anotherNullDecimal));
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
@ -150,8 +151,13 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
}
|
||||
|
||||
public void setValueAsString(String theString) {
|
||||
setValue(new BigDecimal(theString));
|
||||
setRepresentation(theString);
|
||||
if (StringUtils.isBlank(theString)) {
|
||||
setValue((BigDecimal) null);
|
||||
setRepresentation(null);
|
||||
} else {
|
||||
setValue(new BigDecimal(theString));
|
||||
setRepresentation(theString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,11 @@ package org.hl7.fhir.r4.model;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class DecimalTypeNullTest {
|
||||
|
||||
@ -44,4 +49,27 @@ class DecimalTypeNullTest {
|
||||
DecimalType copyDecimal = (DecimalType) nullDecimal.typedCopy();
|
||||
Assertions.assertNull(copyDecimal.getValue());
|
||||
}
|
||||
|
||||
public static Stream<Arguments> provideEmptyOrNullStringsConstructor() {
|
||||
return Stream.of(
|
||||
Arguments.of((String)null),
|
||||
Arguments.of(""),
|
||||
Arguments.of(" ")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideEmptyOrNullStringsConstructor")
|
||||
void testNullValue(String theStringValue) {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
Assertions.assertNull(nullDecimal.getValue());
|
||||
Assertions.assertNull(nullDecimal.asStringValue());
|
||||
|
||||
DecimalType anotherNullDecimal = new DecimalType(theStringValue);
|
||||
Assertions.assertNull(anotherNullDecimal.getValue());
|
||||
Assertions.assertNull(anotherNullDecimal.asStringValue());
|
||||
|
||||
Assertions.assertTrue(nullDecimal.equalsDeep(anotherNullDecimal));
|
||||
Assertions.assertTrue(nullDecimal.equalsShallow(anotherNullDecimal));
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
@ -150,8 +151,13 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
}
|
||||
|
||||
public void setValueAsString(String theString) {
|
||||
setValue(new BigDecimal(theString));
|
||||
setRepresentation(theString);
|
||||
if (StringUtils.isBlank(theString)) {
|
||||
setValue((BigDecimal) null);
|
||||
setRepresentation(null);
|
||||
} else {
|
||||
setValue(new BigDecimal(theString));
|
||||
setRepresentation(theString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,13 @@
|
||||
package org.hl7.fhir.r4b.model;
|
||||
|
||||
import org.hl7.fhir.r4b.model.DecimalType;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class DecimalTypeNullTest {
|
||||
|
||||
@ -45,4 +49,27 @@ class DecimalTypeNullTest {
|
||||
DecimalType copyDecimal = (DecimalType) nullDecimal.typedCopy();
|
||||
Assertions.assertNull(copyDecimal.getValue());
|
||||
}
|
||||
|
||||
public static Stream<Arguments> provideEmptyOrNullStringsConstructor() {
|
||||
return Stream.of(
|
||||
Arguments.of((String)null),
|
||||
Arguments.of(""),
|
||||
Arguments.of(" ")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideEmptyOrNullStringsConstructor")
|
||||
void testNullValue(String theStringValue) {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
Assertions.assertNull(nullDecimal.getValue());
|
||||
Assertions.assertNull(nullDecimal.asStringValue());
|
||||
|
||||
DecimalType anotherNullDecimal = new DecimalType(theStringValue);
|
||||
Assertions.assertNull(anotherNullDecimal.getValue());
|
||||
Assertions.assertNull(anotherNullDecimal.asStringValue());
|
||||
|
||||
Assertions.assertTrue(nullDecimal.equalsDeep(anotherNullDecimal));
|
||||
Assertions.assertTrue(nullDecimal.equalsShallow(anotherNullDecimal));
|
||||
}
|
||||
}
|
@ -1,6 +1,540 @@
|
||||
package org.hl7.fhir.r5.conformance;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.extensions.ExtensionConstants;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Enumeration;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class CapabilityStatementUtilities {
|
||||
private IWorkerContext context;
|
||||
|
||||
public CapabilityStatementUtilities(IWorkerContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolves any imported CapabilityStatements and returns a revised CapabilityStatement that merges all functionality from
|
||||
* the imported CapabilityStatements
|
||||
* @param targetCS - The CapabilityStatement (potentially) containing imports to be resolved
|
||||
* @throws FHIRException - If there's an issue resolving any of the imports
|
||||
*/
|
||||
public CapabilityStatement resolveImports(CapabilityStatement targetCS) throws FHIRException {
|
||||
CapabilityStatement resolvedCS = targetCS.copy();
|
||||
return resolveImports(resolvedCS, new HashMap<>(), "SHALL");
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolves any imported CapabilityStatements and returns a revised CapabilityStatement that merges all functionality from
|
||||
* the imported CapabilityStatements
|
||||
* @param targetCS - The CapabilityStatement (potentially) containing imports to be resolved
|
||||
* @param importedUrls - Keeps track of what CapabilityStatements have already been merged so that if the same CS appears more
|
||||
* than once in the hierarchy, we only process it once. Also keeps track of what 'strength' the import is.
|
||||
* @throws FHIRException - If there's an issue resolving any of the imports
|
||||
*
|
||||
* When processing imports, an imported CapabilityStatement can itself declare a conformance expectation. If an import is a SHOULD or a MAY,
|
||||
* then even if the imported CS asserts something as a SHALL, the highest effective level of conformance for the imported statements is the
|
||||
* conformance level for the import itself. And that cascades. So if a MAY import points to a SHOULD import, the max conformance is 'MAY'.
|
||||
*
|
||||
* The merge process also tackles most of the semantically-significant extensions on CababilityStatement.
|
||||
*
|
||||
* Metadata is not merged - so things like description, publisher, etc. are taken only from the root importing CS.
|
||||
*/
|
||||
public CapabilityStatement resolveImports(CapabilityStatement targetCS, Map<String, String> importedUrls, String conformance) throws FHIRException {
|
||||
if (!targetCS.hasImports())
|
||||
return targetCS;
|
||||
|
||||
CapabilityStatement resolvedCS = targetCS.copy();
|
||||
for (CanonicalType canonical: resolvedCS.getImports()) {
|
||||
CapabilityStatement importedCS = context.fetchResource(CapabilityStatement.class, canonical.getValue());
|
||||
if (importedCS == null)
|
||||
throw new FHIRException("Unable to resolve CapabilityStatement " + canonical.getValue() + " imported by " + targetCS.getUrl());
|
||||
String importConformance = effectiveConformance(canonical.getExtensionString(ToolingExtensions.EXT_CAP_STMT_EXPECT), conformance);
|
||||
if (importedUrls.containsKey(canonical.getValue()) && !importedUrls.get(canonical.getValue()).equals(importConformance)) {
|
||||
throw new FHIRException("The CapabilityStatement " + canonical.getValue() + " is imported with different strengths - " + importedUrls.get(canonical.getValue()).equals(importConformance) + ", " + importConformance +
|
||||
(importConformance.equals(canonical.getExtensionString(ToolingExtensions.EXT_CAP_STMT_EXPECT)) ? "" : "(effective from " + canonical.getExtensionString(ToolingExtensions.EXT_CAP_STMT_EXPECT) + ")"));
|
||||
}
|
||||
importedUrls.put(targetCS.getUrl(), importConformance);
|
||||
|
||||
CapabilityStatement mergedImportedCS = resolveImports(importedCS, importedUrls, importConformance);
|
||||
mergeCS(resolvedCS, mergedImportedCS, importConformance);
|
||||
}
|
||||
|
||||
return resolvedCS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merges the details of an imported capability statement into the 'target' capability statement (which is a copy of the importing CS)
|
||||
* The general import rules are as follows:
|
||||
* - If the importing CS has something and the imported doesn't, grab what the importing does.
|
||||
* - If the imported CS has something and the importing doesn't, grab what the imported does.
|
||||
* - If both do something, combine the functionality and set the conformance expectation to the highest of the two
|
||||
*
|
||||
* Additional rules:
|
||||
* - CS allows you to specify separate messaging repetitions with different combinations of recipients. That gets miserable to try to merge
|
||||
* because the potential recipients can be overlapping. It's also super-rare to do that. So this algorithm only handles merging if there's
|
||||
* a maximum of one messaging element (though that one element can list lots of supported messages)
|
||||
* - If there's non-repeating elements with different values, grab the one with the highest conformance expectation. If the conformance levels
|
||||
* are the same, then fail due to the conflict. For example, if one says SHOULD security.cors = true and the other says SHALL security.cors = false,
|
||||
* then the SHALL takes precedence. On the other hand, if both say SHOULD with different values, that's conflict and will trigger an exception.
|
||||
* - For certain 'coded' elements there's a hierarchy. versioned-update implies versioned. So if you have SHOULD:versioned and SHOULD:versioned-update,
|
||||
* that's *not* a conflict and you'll end up with SHOULD:versioned-update. (Hierarchies are handled by the weightForEnum function.)
|
||||
* - For numeric values, will take the strictest. So for timeout values, if there is a SHOULD:5seconds and SHOULD:10 seconds, you'll get SHOULD:5 seconds
|
||||
* - For coded values, a match means all codings match (code, system, and version if present) and text matches. Display names are ignored
|
||||
* - It's also a conflict if:
|
||||
* - the same operation 'code' is associated with different operation definitions
|
||||
* - the same search parameter 'code' is associated with different search parameter definitions
|
||||
* - the same rest.resource is tied to different profiles. (We could try to be smart and figure out if the imported profile is a proper subset of the
|
||||
* importing profile, but that was too hard to take on at this point)
|
||||
* - An imported search combination has more 'optional' elements than the importing search combination
|
||||
* - The following are additional limitations
|
||||
* - Can't handle endpoints on an imported CS. (That's a super-weird situation and couldn't decide what to do about it.) Same is true for importing
|
||||
* a CS with messages that declare endpoints
|
||||
*
|
||||
*
|
||||
*/
|
||||
protected void mergeCS(CapabilityStatement targetCS, CapabilityStatement importedCS, String maxConformance) {
|
||||
merge(targetCS.getFormat(), importedCS.getFormat(), maxConformance, "format");
|
||||
merge(targetCS.getPatchFormat(), importedCS.getPatchFormat(), maxConformance, "patchFormat");
|
||||
merge(targetCS.getAcceptLanguage(), importedCS.getAcceptLanguage(), maxConformance, "acceptLanguage");
|
||||
merge(targetCS.getImplementationGuide(), importedCS.getImplementationGuide(), maxConformance, "implementationGuide");
|
||||
merge(targetCS.getRest(), importedCS.getRest(), maxConformance, "rest");
|
||||
if (targetCS.getMessaging().size()>1)
|
||||
throw new FHIRException("Unable to handle messaging repetitions greater than one for importing Capability Statement - use one repetition with multiple messaging.supportedMessage elements.");
|
||||
else if (importedCS.getMessaging().size()>1)
|
||||
throw new FHIRException("Unable to handle messaging repetitions greater than one for imported Capability Statement - use one repetition with multiple messaging.supportedMessage elements.");
|
||||
else if (!importedCS.hasMessaging()) {
|
||||
// Do nothing
|
||||
} else if (!targetCS.hasMessaging())
|
||||
targetCS.setMessaging(importedCS.getMessaging());
|
||||
else {
|
||||
CapabilityStatement.CapabilityStatementMessagingComponent targetMessaging = targetCS.getMessaging().get(0);
|
||||
CapabilityStatement.CapabilityStatementMessagingComponent importedMessaging = importedCS.getMessaging().get(0);
|
||||
merge(targetMessaging.getReliableCacheElement(), importedMessaging.getReliableCacheElement(), maxConformance, "messaging.reliableCache");
|
||||
if (importedMessaging.hasEndpoint())
|
||||
throw new FHIRException("Importing capability statements that assert endpoints is not supported");
|
||||
merge(targetMessaging.getSupportedMessage(), importedMessaging.getSupportedMessage(), maxConformance, "messaging.supportedMessage");
|
||||
}
|
||||
merge(targetCS.getMessaging(), importedCS.getMessaging(), maxConformance, "messaging");
|
||||
merge(targetCS.getDocument(), importedCS.getDocument(), maxConformance, "messaging");
|
||||
}
|
||||
|
||||
void mergeProperties(CapabilityStatement.CapabilityStatementRestComponent targetType, CapabilityStatement.CapabilityStatementRestComponent importedType, String maxConformance, String context) {
|
||||
String localContext = context + "." + targetType.getMode();
|
||||
|
||||
merge(targetType.getExtensionsByUrl(ExtensionConstants.EXT_CSDECLARED_PROFILE), importedType.getExtensionsByUrl(ExtensionConstants.EXT_CSDECLARED_PROFILE), maxConformance, ".extension(DeclaredProfile)");
|
||||
merge(targetType.getExtensionsByUrl(ExtensionConstants.EXT_CSSEARCH_PARAMETER_COMBINATION), importedType.getExtensionsByUrl(ExtensionConstants.EXT_CSSEARCH_PARAMETER_COMBINATION), maxConformance, ".extension(SearchMode)");
|
||||
if (!targetType.hasSecurity())
|
||||
targetType.setSecurity(importedType.getSecurity());
|
||||
else if (!importedType.hasSecurity())
|
||||
return;
|
||||
else {
|
||||
mergeProperties(targetType.getSecurity(), importedType.getSecurity(), maxConformance, localContext);
|
||||
mergeExpectations(targetType.getSecurity(), importedType.getSecurity(), maxConformance);
|
||||
}
|
||||
merge(targetType.getResource(), importedType.getResource(), maxConformance, localContext + ".resource");
|
||||
merge(targetType.getInteraction(), importedType.getInteraction(), maxConformance, localContext + ".interaction");
|
||||
merge(targetType.getOperation(), importedType.getOperation(), maxConformance, localContext + ".operation");
|
||||
merge(targetType.getSearchParam(), importedType.getSearchParam(), maxConformance, localContext + ".searchParam");
|
||||
}
|
||||
|
||||
/*
|
||||
* Merges the properties of two RestSecurity components together
|
||||
* NOTE: Doesn't merge documentation or extensions
|
||||
*/
|
||||
// TODO: Handle known security extensions
|
||||
void mergeProperties(CapabilityStatement.CapabilityStatementRestSecurityComponent targetType, CapabilityStatement.CapabilityStatementRestSecurityComponent importedType, String maxConformance, String context) {
|
||||
merge(targetType.getCorsElement(), importedType.getCorsElement(), maxConformance, context + ".cors");
|
||||
merge(targetType.getService(), importedType.getService(), maxConformance, context + ".service");
|
||||
}
|
||||
|
||||
void mergeProperties(CapabilityStatement.CapabilityStatementRestResourceComponent targetType, CapabilityStatement.CapabilityStatementRestResourceComponent importedType, String maxConformance, String context) throws FHIRException {
|
||||
String localContext = context + "." + targetType.getType();
|
||||
if (targetType.hasProfile() && importedType.hasProfile() && !targetType.getProfile().equals(importedType.getProfile()))
|
||||
throw new FHIRException("Conflicting resource profiles for " + localContext + ". If both the importing and imported CapabilityStatement declare profiles for the same resource, those profiles must be the same." +
|
||||
"Importing: " + targetType.getProfile() + "; Imported: " + importedType.getProfile());
|
||||
merge(targetType.getSupportedProfile(), importedType.getSupportedProfile(), maxConformance, localContext + ".supportedProfile");
|
||||
targetType.setVersioningElement(merge(targetType.getVersioningElement(), importedType.getVersioningElement(), maxConformance, localContext + ".versioning"));
|
||||
merge(targetType.getInteraction(), importedType.getInteraction(), maxConformance, localContext + ".interaction");
|
||||
targetType.setReadHistoryElement(merge(targetType.getReadHistoryElement(), importedType.getReadHistoryElement(), maxConformance, localContext + ".readHistory"));
|
||||
targetType.setUpdateCreateElement(merge(targetType.getUpdateCreateElement(), importedType.getUpdateCreateElement(), maxConformance, localContext + ".updateCreate"));
|
||||
targetType.setConditionalCreateElement(merge(targetType.getConditionalCreateElement(), importedType.getConditionalCreateElement(), maxConformance, localContext + ".conditionalCreate"));
|
||||
targetType.setConditionalReadElement(merge(targetType.getConditionalReadElement(), importedType.getConditionalReadElement(), maxConformance, localContext + ".conditionalRead"));
|
||||
targetType.setConditionalPatchElement(merge(targetType.getConditionalPatchElement(), importedType.getConditionalPatchElement(), maxConformance, localContext + ".conditionalPatch"));
|
||||
targetType.setConditionalDeleteElement(merge(targetType.getConditionalDeleteElement(), importedType.getConditionalDeleteElement(), maxConformance, localContext + ".conditionalDelete"));
|
||||
merge(targetType.getReferencePolicy(), importedType.getReferencePolicy(), maxConformance, localContext + ".referencePolicy");
|
||||
merge(targetType.getSearchInclude(), importedType.getSearchInclude(), maxConformance, localContext + ".searchInclude");
|
||||
merge(targetType.getSearchRevInclude(), importedType.getSearchRevInclude(), maxConformance, localContext + ".searchRevInclude");
|
||||
merge(targetType.getSearchParam(), importedType.getSearchParam(), maxConformance, localContext + ".searchParam");
|
||||
merge(targetType.getOperation(), importedType.getOperation(), maxConformance, localContext + ".operation");
|
||||
}
|
||||
|
||||
void mergeProperties(CapabilityStatement.CapabilityStatementRestResourceOperationComponent targetType, CapabilityStatement.CapabilityStatementRestResourceOperationComponent importedType, String context) throws FHIRException {
|
||||
String localContext = context + "(name=" + targetType.getName() + ")";
|
||||
if (!importedType.hasDefinition()) {
|
||||
// do nothing
|
||||
} else if (!targetType.hasDefinition())
|
||||
targetType.setDefinitionElement(importedType.getDefinitionElement());
|
||||
else if (!targetType.getDefinition().equals(importedType.getDefinition()))
|
||||
throw new FHIRException("Differing definitions for same operation " + localContext + " in imported IG. Importing:" + targetType.getDefinition() + "; imported:" + importedType.getDefinition());
|
||||
}
|
||||
|
||||
void mergeProperties(CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent targetType, CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent importedType, String maxConformance, String context) throws FHIRException {
|
||||
String localContext = context + "(name=" + targetType.getName() + ")";
|
||||
if (!importedType.hasDefinition()) {
|
||||
// do nothing
|
||||
} else if (!targetType.hasDefinition()) {
|
||||
targetType.setDefinitionElement((CanonicalType)fixMax(importedType.getDefinitionElement(), maxConformance));
|
||||
} else if (!targetType.getDefinition().equals(importedType.getDefinition()))
|
||||
throw new FHIRException("Differing definitions for same Search parameter " + localContext + " in imported IG. Importing:" + targetType.getDefinition() + "; imported:" + importedType.getDefinition());
|
||||
if (!importedType.hasType()) {
|
||||
// do nothing
|
||||
} else if (!targetType.hasType()) {
|
||||
targetType.setTypeElement((Enumeration<Enumerations.SearchParamType>)fixMax(importedType.getTypeElement(), maxConformance));
|
||||
} else if (!targetType.getType().equals(importedType.getType()))
|
||||
throw new FHIRException("Differing search types for same Search parameter " + localContext + " in imported IG. Importing:" + targetType.getType() + "; imported:" + importedType.getType());
|
||||
}
|
||||
|
||||
void mergeProperties(CapabilityStatement.CapabilityStatementMessagingComponent targetType, CapabilityStatement.CapabilityStatementMessagingComponent importedType, String maxConformance, String context) throws FHIRException {
|
||||
if (importedType.hasEndpoint()) {
|
||||
throw new FHIRException("Cannot handle importing messaging with declared endpoints");
|
||||
}
|
||||
targetType.setReliableCacheElement(merge(targetType.getReliableCacheElement(), importedType.getReliableCacheElement(), maxConformance, context + ".reliableCache"));
|
||||
merge(targetType.getSupportedMessage(), importedType.getSupportedMessage(), maxConformance, context + ".reliableCache");
|
||||
}
|
||||
|
||||
void merge(List targetList, List importedList, String context) throws FHIRException {
|
||||
merge(targetList, importedList, "SHALL", context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Combines any 'simple' types found in the 'imported' list into the target list, merging conformance expectations found on matching codes
|
||||
*/
|
||||
void merge(List targetList, List importedList, String maxConformance, String context) throws FHIRException {
|
||||
for (Object importedType : importedList) {
|
||||
Object foundType = null;
|
||||
for (Object targetType : targetList) {
|
||||
boolean match;
|
||||
if (targetType instanceof PrimitiveType)
|
||||
match = importedType.toString().equals(targetType.toString());
|
||||
else if (importedType instanceof CodeableConcept)
|
||||
match = match((CodeableConcept)targetType,(CodeableConcept)importedType);
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementRestComponent)
|
||||
match = ((CapabilityStatement.CapabilityStatementRestComponent)targetType).getMode().equals(((CapabilityStatement.CapabilityStatementRestComponent)importedType).getMode());
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementRestResourceComponent)
|
||||
match = ((CapabilityStatement.CapabilityStatementRestResourceComponent)targetType).getType().equals(((CapabilityStatement.CapabilityStatementRestResourceComponent)importedType).getType());
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementRestResourceOperationComponent)
|
||||
match = ((CapabilityStatement.CapabilityStatementRestResourceOperationComponent)targetType).getName().equals(((CapabilityStatement.CapabilityStatementRestResourceOperationComponent)importedType).getName());
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent)
|
||||
match = ((CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent)targetType).getName().equals(((CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent)importedType).getName());
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementMessagingComponent)
|
||||
match = true; // We only work if there's only one messaging component in each
|
||||
else if (importedType instanceof CapabilityStatement.ResourceInteractionComponent)
|
||||
match = ((CapabilityStatement.ResourceInteractionComponent)targetType).getCode().equals(((CapabilityStatement.ResourceInteractionComponent)importedType).getCode());
|
||||
else if (importedType instanceof CapabilityStatement.SystemInteractionComponent)
|
||||
match = ((CapabilityStatement.SystemInteractionComponent)targetType).getCode().equals(((CapabilityStatement.SystemInteractionComponent)importedType).getCode());
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementDocumentComponent)
|
||||
match = ((CapabilityStatement.CapabilityStatementDocumentComponent)targetType).getMode().equals(((CapabilityStatement.CapabilityStatementDocumentComponent)importedType).getMode()) &&
|
||||
((CapabilityStatement.CapabilityStatementDocumentComponent)targetType).getProfile().equals(((CapabilityStatement.CapabilityStatementDocumentComponent)importedType).getProfile());
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementMessagingSupportedMessageComponent)
|
||||
match = ((CapabilityStatement.CapabilityStatementMessagingSupportedMessageComponent)targetType).getMode().equals(((CapabilityStatement.CapabilityStatementMessagingSupportedMessageComponent)importedType).getMode())
|
||||
&& ((CapabilityStatement.CapabilityStatementMessagingSupportedMessageComponent)targetType).getDefinition().equals(((CapabilityStatement.CapabilityStatementMessagingSupportedMessageComponent)importedType).getDefinition());
|
||||
else if (importedType instanceof Extension) {
|
||||
if (((Extension)importedType).getUrl().equals(ExtensionConstants.EXT_CSDECLARED_PROFILE))
|
||||
match = ((Extension)targetType).getValueCanonicalType().getValue().equals(((Extension)importedType).getValueCanonicalType().getValue());
|
||||
else if (((Extension)importedType).getUrl().equals(ExtensionConstants.EXT_CSSEARCH_PARAMETER_COMBINATION)) {
|
||||
match = requiredSort(targetType).equals(requiredSort(importedType));
|
||||
} else
|
||||
throw new Error("Unexpected extension " + ((Extension)importedType).getUrl());
|
||||
} else
|
||||
throw new Error("Unhandled complex type in List match");
|
||||
if (match){
|
||||
foundType = targetType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundType == null)
|
||||
targetList.add(importedType);
|
||||
else {
|
||||
if (importedType instanceof PrimitiveType) {
|
||||
// No properties to merge
|
||||
} else if (importedType instanceof CapabilityStatement.CapabilityStatementRestComponent)
|
||||
mergeProperties((CapabilityStatement.CapabilityStatementRestComponent)foundType, (CapabilityStatement.CapabilityStatementRestComponent)importedType, maxConformance, context);
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementRestResourceComponent)
|
||||
mergeProperties((CapabilityStatement.CapabilityStatementRestResourceComponent)foundType, (CapabilityStatement.CapabilityStatementRestResourceComponent)importedType, maxConformance, context);
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementRestResourceOperationComponent)
|
||||
mergeProperties((CapabilityStatement.CapabilityStatementRestResourceOperationComponent)foundType, (CapabilityStatement.CapabilityStatementRestResourceOperationComponent)importedType, context);
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent)
|
||||
mergeProperties((CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent)foundType, (CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent)importedType, maxConformance, context);
|
||||
else if (importedType instanceof CapabilityStatement.ResourceInteractionComponent || importedType instanceof CapabilityStatement.SystemInteractionComponent) {
|
||||
// No properties to merge
|
||||
} else if (importedType instanceof CapabilityStatement.CapabilityStatementDocumentComponent) {
|
||||
// No properties to merge
|
||||
} else if (importedType instanceof CapabilityStatement.CapabilityStatementMessagingComponent)
|
||||
mergeProperties((CapabilityStatement.CapabilityStatementMessagingComponent)foundType, (CapabilityStatement.CapabilityStatementMessagingComponent)importedType, maxConformance, context);
|
||||
else if (importedType instanceof CapabilityStatement.CapabilityStatementMessagingSupportedMessageComponent) {
|
||||
// No properties to merge
|
||||
} else if (importedType instanceof Extension) {
|
||||
if (((Extension) importedType).getUrl().equals(ExtensionConstants.EXT_CSDECLARED_PROFILE)) {
|
||||
// No action needed
|
||||
} else if (((Extension) importedType).getUrl().equals(ExtensionConstants.EXT_CSSEARCH_PARAMETER_COMBINATION))
|
||||
mergeSearchComboExt(((Extension) foundType), ((Extension) importedType), context + ".extension(SearchCombo - " + requiredSort(importedType) + ")");
|
||||
}
|
||||
mergeExpectations((Element) foundType, (Element) importedType, maxConformance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Two CodeableConcepts match if they have the same text and their codings match by code + system (and version if present)
|
||||
*/
|
||||
private boolean match(CodeableConcept a, CodeableConcept b) {
|
||||
if (a.hasText() || b.hasText())
|
||||
if (a.hasText()!= b.hasText() || !a.getText().equals(b.getText()))
|
||||
return false;
|
||||
if (a.getCoding().size()!= b.getCoding().size())
|
||||
return false;
|
||||
for (Coding codeA: a.getCoding()) {
|
||||
boolean codingMatch = false;
|
||||
for (Coding codeB: b.getCoding()) {
|
||||
if (codeA.hasSystem() != codeB.hasSystem())
|
||||
continue;
|
||||
if (codeA.hasSystem() && !codeA.getSystem().equals(codeB.getSystem()))
|
||||
continue;
|
||||
if (codeA.hasCode() != codeB.hasCode())
|
||||
continue;
|
||||
if (codeA.hasCode() && !codeA.getCode().equals(codeB.getCode()))
|
||||
continue;
|
||||
if (codeA.hasVersion() != codeB.hasVersion())
|
||||
continue;
|
||||
if (codeA.hasVersion() && !codeA.getVersion().equals(codeB.getVersion()))
|
||||
continue;
|
||||
codingMatch = true;
|
||||
break;
|
||||
}
|
||||
if (!codingMatch)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<String> extensionValueList(Extension sortExtension, String url) {
|
||||
List<String> aList = new ArrayList<>();
|
||||
for (Extension e: sortExtension.getExtensionsByUrl(url)) {
|
||||
aList.add(e.getValueStringType().toString());
|
||||
}
|
||||
aList.sort(new Utilities.CaseInsensitiveSorter());
|
||||
return aList;
|
||||
}
|
||||
|
||||
private String requiredSort(Object sortExtension) {
|
||||
return String.join(";", extensionValueList((Extension)sortExtension, "required"));
|
||||
}
|
||||
|
||||
private void mergeSearchComboExt(Extension targetExt, Extension importedExt, String context) {
|
||||
List<String> targetList = extensionValueList(targetExt, "otional");
|
||||
List<String> importedList = extensionValueList(importedExt, "otional");
|
||||
if (!targetList.containsAll(importedList))
|
||||
throw new FHIRException("Search Options extension for " + context + " does not contain all of the optional search names from the imported CapabilityStatement, which is not supported.");
|
||||
}
|
||||
|
||||
private UnsignedIntType merge(UnsignedIntType targetInt, UnsignedIntType importedInt, String context) throws FHIRException {
|
||||
return merge(targetInt, importedInt, "SHALL", context);
|
||||
}
|
||||
|
||||
private UnsignedIntType merge(UnsignedIntType targetInt, UnsignedIntType importedInt, String maxConformance, String context) throws FHIRException {
|
||||
if (targetInt == null)
|
||||
return importedInt;
|
||||
else if (importedInt == null)
|
||||
return (UnsignedIntType)fixMax(targetInt, context);
|
||||
else if (targetInt.getValue().equals(importedInt.getValue())) {
|
||||
mergeExpectations(targetInt, importedInt, maxConformance);
|
||||
return targetInt;
|
||||
} else if (targetInt.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT) && importedInt.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
|
||||
String targetExpectation = targetInt.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode();
|
||||
String importedExpectation = importedInt.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode();
|
||||
if (targetExpectation.equals(importedExpectation)) {
|
||||
if (targetExpectation.equals("SHALL"))
|
||||
throw new FHIRException("Non matching enumeration values with SHALL conformance expectations for " + context + " - base CapabilityStatement:" + targetInt.getValue() + "; imported CapabilityStatement:" + importedInt.getValue());
|
||||
else if (targetInt.getValue() > importedInt.getValue())
|
||||
return targetInt;
|
||||
else
|
||||
return (UnsignedIntType)fixMax(importedInt, maxConformance);
|
||||
} else {
|
||||
if (targetExpectation.equals("SHALL"))
|
||||
return targetInt;
|
||||
else if (importedExpectation.equals("SHALL"))
|
||||
return (UnsignedIntType)fixMax(importedInt, maxConformance);
|
||||
else if (targetInt.getValue() > importedInt.getValue())
|
||||
return targetInt;
|
||||
else
|
||||
return importedInt;
|
||||
}
|
||||
}
|
||||
throw new FHIRException("Non matching integer values for " + context + " - base CapabilityStatement:" + targetInt.getValue() + "; imported CapabilityStatement:" + importedInt.getValue());
|
||||
}
|
||||
|
||||
|
||||
private Enumeration merge(Enumeration targetCode, Enumeration importedCode, String context) throws FHIRException {
|
||||
return merge(targetCode, importedCode, "SHALL", context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Selects whichever code exists if only one exists, otherwise checks that the two codes match and merges conformance expectations
|
||||
*/
|
||||
private Enumeration merge(Enumeration targetCode, Enumeration importedCode, String maxConformance, String context) throws FHIRException {
|
||||
if (targetCode == null || targetCode.getCode() == null)
|
||||
return (Enumeration)fixMax(importedCode, maxConformance);
|
||||
else if (importedCode == null || importedCode.getCode() == null)
|
||||
return targetCode;
|
||||
else if (targetCode.getValue().equals(importedCode.getValue())) {
|
||||
mergeExpectations(targetCode, importedCode, maxConformance);
|
||||
return targetCode;
|
||||
} else if (targetCode.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT) && importedCode.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
|
||||
String targetExpectation = targetCode.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode();
|
||||
String importedExpectation = importedCode.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode();
|
||||
int targetWeight = weightForEnum(targetCode, context);
|
||||
int importedWeight = weightForEnum(importedCode, context);
|
||||
if (targetExpectation.equals(importedExpectation)) {
|
||||
if (targetExpectation.equals("SHALL"))
|
||||
throw new FHIRException("Non matching enumeration values with SHALL conformance expectations for " + context + " - base CapabilityStatement:" + targetCode.getValue() + "; imported CapabilityStatement:" + importedCode.getValue());
|
||||
else if (targetWeight == importedWeight)
|
||||
throw new FHIRException("Non matching enumeration values with equivalent weight and identical conformance expectations for " + context + " - base CapabilityStatement:" + targetCode.getValue() + "; imported CapabilityStatement:" + importedCode.getValue());
|
||||
else if (targetWeight > importedWeight)
|
||||
return targetCode;
|
||||
else
|
||||
return (Enumeration)fixMax(importedCode, maxConformance);
|
||||
} else {
|
||||
if (targetExpectation.equals("SHALL"))
|
||||
return targetCode;
|
||||
else if (importedExpectation.equals("SHALL"))
|
||||
return (Enumeration)fixMax(importedCode, maxConformance);
|
||||
else if (targetWeight == importedWeight)
|
||||
throw new FHIRException("Non matching enumeration values with equivalent weight and optional conformance expectations for " + context + " - base CapabilityStatement:" + targetCode.getValue() + "; imported CapabilityStatement:" + importedCode.getValue());
|
||||
else if (targetWeight > importedWeight)
|
||||
return targetCode;
|
||||
else
|
||||
return (Enumeration)fixMax(importedCode, maxConformance);
|
||||
}
|
||||
}
|
||||
throw new FHIRException("Non matching code values for " + context + " - base CapabilityStatement:" + targetCode.getCode() + "; imported CapabilityStatement:" + importedCode.getCode());
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a numeric weight for enumeration codes that represent differing levels of sophistication.
|
||||
* Lower numbers imply lesser functionality that is implicitly included in higher numbers. I.e. If you have a higher number it means you support the functionality of the lower numbers
|
||||
*/
|
||||
private int weightForEnum(Enumeration code, String context) {
|
||||
switch (code.getSystem()) {
|
||||
case "http://hl7.org/fhir/conditional-delete-status":
|
||||
CapabilityStatement.ConditionalDeleteStatus deleteStatus = CapabilityStatement.ConditionalDeleteStatus.fromCode(code.getCode());
|
||||
switch (deleteStatus) {
|
||||
case NOTSUPPORTED:
|
||||
return 0;
|
||||
case SINGLE:
|
||||
return 1;
|
||||
case MULTIPLE:
|
||||
return 2;
|
||||
default:
|
||||
throw new FHIRException("Unrecognized Delete Status in " + context + ": " + code.getCode());
|
||||
}
|
||||
case "http://hl7.org/fhir/conditional-read-status":
|
||||
CapabilityStatement.ConditionalReadStatus readStatus = CapabilityStatement.ConditionalReadStatus.fromCode(code.getCode());
|
||||
switch (readStatus) {
|
||||
case NOTSUPPORTED:
|
||||
return 0;
|
||||
case MODIFIEDSINCE:
|
||||
return 1;
|
||||
case NOTMATCH:
|
||||
return 1; // Same weight as MODIFIEDSINCE
|
||||
case FULLSUPPORT:
|
||||
return 2;
|
||||
default:
|
||||
throw new FHIRException("Unrecognized Read Status in " + context + ": " + code.getCode());
|
||||
}
|
||||
case "http://hl7.org/fhir/versioning-policy":
|
||||
CapabilityStatement.ResourceVersionPolicy versionPolicy = CapabilityStatement.ResourceVersionPolicy.fromCode(code.getCode());
|
||||
switch (versionPolicy) {
|
||||
case NOVERSION:
|
||||
return 0;
|
||||
case VERSIONED:
|
||||
return 1;
|
||||
case VERSIONEDUPDATE:
|
||||
return 2;
|
||||
default:
|
||||
throw new FHIRException("Unrecognized Versioning Policy in " + context + ": " + code.getCode());
|
||||
}
|
||||
}
|
||||
throw new Error("Unsupported code system in " + context + ": " + code.getSystem());
|
||||
}
|
||||
|
||||
protected BooleanType merge(BooleanType targetBool, BooleanType importedBool, String context) throws FHIRException {
|
||||
return merge(targetBool, importedBool, "SHALL", context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Selects whichever code exists if only one exists, otherwise checks that the two codes match and merges conformance expectations
|
||||
*/
|
||||
protected BooleanType merge(BooleanType targetBool, BooleanType importedBool, String maxConformance, String context) throws FHIRException {
|
||||
if (targetBool == null || targetBool.getValue() == null)
|
||||
return (BooleanType)fixMax(importedBool,maxConformance);
|
||||
else if (importedBool == null || importedBool.getValue() == null)
|
||||
return targetBool;
|
||||
else if (targetBool.getValue().equals(importedBool.getValue())) {
|
||||
mergeExpectations(targetBool, importedBool, maxConformance);
|
||||
return targetBool;
|
||||
} else if (targetBool.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT) && importedBool.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
|
||||
String targetExpectation = targetBool.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode();
|
||||
String importedExpectation = importedBool.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode();
|
||||
if (targetExpectation.equals(importedExpectation))
|
||||
throw new FHIRException("Non matching boolean values with equivalent conformance expectations for " + context + " - base CapabilityStatement:" + targetBool.getValue() + "; imported CapabilityStatement:" + importedBool.getValue());
|
||||
else if (targetExpectation.equals("SHALL"))
|
||||
return targetBool;
|
||||
else if (importedExpectation.equals("SHALL"))
|
||||
return (BooleanType)fixMax(importedBool, maxConformance);
|
||||
else if (targetExpectation.equals("SHOULD"))
|
||||
return targetBool;
|
||||
else if (importedExpectation.equals("SHOULD"))
|
||||
return (BooleanType)fixMax(importedBool, maxConformance);
|
||||
}
|
||||
throw new FHIRException("Non matching boolean values with no conformance expectations for " + context + " - base CapabilityStatement:" + targetBool.getValue() + "; imported CapabilityStatement:" + importedBool.getValue());
|
||||
}
|
||||
|
||||
|
||||
public void mergeExpectations(Element target, Element source, String maxConformance) {
|
||||
if (target.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
|
||||
Extension targetExpectation = target.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT);
|
||||
if (!targetExpectation.getValueCodeType().getCode().equals("SHALL") && source.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
|
||||
String sourceExpectation = effectiveConformance(source.getExtensionString(ToolingExtensions.EXT_CAP_STMT_EXPECT), maxConformance);
|
||||
if (sourceExpectation.equals("SHALL") || targetExpectation.getValueCodeType().getCode().equals("MAY"))
|
||||
targetExpectation.setValue(new CodeType(sourceExpectation));
|
||||
}
|
||||
} else if (source.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
|
||||
target.addExtension(source.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT));
|
||||
}
|
||||
}
|
||||
|
||||
private String effectiveConformance(String conf, String maxConf) {
|
||||
conf = conf==null ? "SHALL" : conf;
|
||||
maxConf = maxConf==null ? "SHALL" : maxConf;
|
||||
if (conf.equals(maxConf))
|
||||
return conf;
|
||||
else if (conf.equals("SHALL"))
|
||||
return maxConf;
|
||||
else if (maxConf.equals("SHALL") || maxConf.equals("SHOULD"))
|
||||
return conf;
|
||||
else
|
||||
return maxConf;
|
||||
}
|
||||
|
||||
public DataType fixMax(DataType d, String maxConformance) {
|
||||
String conformance = d.getExtensionString(ToolingExtensions.EXT_CAP_STMT_EXPECT);
|
||||
d.removeExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT);
|
||||
d.addExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT, new CodeType(effectiveConformance(conformance, maxConformance)));
|
||||
return d;
|
||||
}
|
||||
}
|
@ -1,33 +1,33 @@
|
||||
package org.hl7.fhir.r5.model;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -66,7 +66,11 @@ public class CodeType extends StringType implements Comparable<CodeType>, ICodin
|
||||
return 1;
|
||||
}
|
||||
return defaultString(getValue()).compareTo(defaultString(theCode.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(CodeType theCode) {
|
||||
return this.getCode().equals(theCode.getCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parse(String theValue) {
|
||||
|
@ -35,6 +35,7 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
@ -166,8 +167,13 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
}
|
||||
|
||||
public void setValueAsString(String theString) {
|
||||
setValue(new BigDecimal(theString));
|
||||
setRepresentation(theString);
|
||||
if (StringUtils.isBlank(theString)) {
|
||||
setValue((BigDecimal) null);
|
||||
setRepresentation(null);
|
||||
} else {
|
||||
setValue(new BigDecimal(theString));
|
||||
setRepresentation(theString);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -184,7 +190,7 @@ public class DecimalType extends PrimitiveType<BigDecimal> implements Comparable
|
||||
/**
|
||||
* A parser can provide a literal representation for the decimal value that preserves
|
||||
* the presented form.
|
||||
*
|
||||
* <p/>
|
||||
* All sorts of bad things can happen if this method is used to set the string representation
|
||||
* to anything other than what was parsed into the actual value. Don't do that
|
||||
*
|
||||
|
@ -1,33 +1,33 @@
|
||||
package org.hl7.fhir.r5.model;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -206,9 +206,9 @@ public abstract class PrimitiveType<T> extends DataType implements IPrimitiveTyp
|
||||
else
|
||||
return super.setProperty(name, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(String name, Base value) throws FHIRException {
|
||||
if (name.equals("value"))
|
||||
setValueAsString(value.toString());
|
||||
@ -246,7 +246,7 @@ public abstract class PrimitiveType<T> extends DataType implements IPrimitiveTyp
|
||||
}
|
||||
|
||||
/*
|
||||
* this is a work around for representation issues with Bigdecimal. So comments in DecimaType.
|
||||
* this is a workaround for representation issues with BigDecimal. So comments in DecimalType.
|
||||
* Yes, you can cut yourself with this method...
|
||||
*/
|
||||
protected void forceStringValue(String value) {
|
||||
|
@ -3,6 +3,12 @@ package org.hl7.fhir.r5.model;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class DecimalTypeNullTest {
|
||||
|
||||
@ -44,4 +50,27 @@ class DecimalTypeNullTest {
|
||||
DecimalType copyDecimal = (DecimalType) nullDecimal.typedCopy();
|
||||
Assertions.assertNull(copyDecimal.getValue());
|
||||
}
|
||||
|
||||
public static Stream<Arguments> provideEmptyOrNullStringsConstructor() {
|
||||
return Stream.of(
|
||||
Arguments.of((String)null),
|
||||
Arguments.of(""),
|
||||
Arguments.of(" ")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideEmptyOrNullStringsConstructor")
|
||||
void testNullValue(String theStringValue) {
|
||||
DecimalType nullDecimal = new DecimalType();
|
||||
Assertions.assertNull(nullDecimal.getValue());
|
||||
Assertions.assertNull(nullDecimal.asStringValue());
|
||||
|
||||
DecimalType anotherNullDecimal = new DecimalType(theStringValue);
|
||||
Assertions.assertNull(anotherNullDecimal.getValue());
|
||||
Assertions.assertNull(anotherNullDecimal.asStringValue());
|
||||
|
||||
Assertions.assertTrue(nullDecimal.equalsDeep(anotherNullDecimal));
|
||||
Assertions.assertTrue(nullDecimal.equalsShallow(anotherNullDecimal));
|
||||
}
|
||||
}
|
@ -0,0 +1,412 @@
|
||||
package org.hl7.fhir.r5.utils;
|
||||
|
||||
import org.apache.commons.io.output.ByteArrayOutputStream;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.conformance.CapabilityStatementUtilities;
|
||||
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.context.ContextUtilities;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.formats.XmlParser;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
class CapabilityStatementUtilitiesTests {
|
||||
|
||||
private static final String SHALL = "SHALL";
|
||||
private static final String SHOULD = "SHOULD";
|
||||
private static final String MAY = "MAY";
|
||||
private static final Enumeration VP_NOVERSION = (new CapabilityStatement.ResourceVersionPolicyEnumFactory()).fromType(new CodeType("no-version"));
|
||||
private static final Enumeration VP_VERSIONED = (new CapabilityStatement.ResourceVersionPolicyEnumFactory()).fromType(new CodeType("versioned"));
|
||||
private static final Enumeration VP_VERSIONEDUPDATE = (new CapabilityStatement.ResourceVersionPolicyEnumFactory()).fromType(new CodeType("versioned-update"));
|
||||
private static final Enumeration CD_NOTSUPPORTED = (new CapabilityStatement.ConditionalDeleteStatusEnumFactory()).fromType(new CodeType("not-supported"));
|
||||
private static final Enumeration CD_SINGLE = (new CapabilityStatement.ConditionalDeleteStatusEnumFactory()).fromType(new CodeType("single"));
|
||||
private static final Enumeration CD_MULTIPLE = (new CapabilityStatement.ConditionalDeleteStatusEnumFactory()).fromType(new CodeType("multiple"));
|
||||
private static final Enumeration CR_NOTSUPPORTED = (new CapabilityStatement.ConditionalReadStatusEnumFactory()).fromType(new CodeType("not-supported"));
|
||||
private static final Enumeration CR_MODIFIEDSINCE = (new CapabilityStatement.ConditionalReadStatusEnumFactory()).fromType(new CodeType("modified-since"));
|
||||
private static final Enumeration CR_NOTMATCH = (new CapabilityStatement.ConditionalReadStatusEnumFactory()).fromType(new CodeType("not-match"));
|
||||
private static final Enumeration CR_FULLSUPPORT = (new CapabilityStatement.ConditionalReadStatusEnumFactory()).fromType(new CodeType("full-support"));
|
||||
|
||||
private CapabilityStatementUtilities csu;
|
||||
private IWorkerContext ctxt;
|
||||
|
||||
CapabilityStatementUtilitiesTests() {
|
||||
ctxt = TestingUtilities.getSharedWorkerContext();
|
||||
csu = new CapabilityStatementUtilities(ctxt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverall() {
|
||||
IParser p = new XmlParser(false);
|
||||
|
||||
CapabilityStatement c1 = null;
|
||||
CapabilityStatement c2 = null;
|
||||
CapabilityStatement expected = null;
|
||||
try {
|
||||
InputStream strm1 = TestingUtilities.loadTestResourceStream("r5", "capabilitystatement-import", "CapabilityStatement-1.xml");
|
||||
InputStream strm2 = TestingUtilities.loadTestResourceStream("r5", "capabilitystatement-import", "CapabilityStatement-2.xml");
|
||||
InputStream strm3 = TestingUtilities.loadTestResourceStream("r5", "capabilitystatement-import", "CapabilityStatement-2merged.xml");
|
||||
c1 = (CapabilityStatement)p.parse(strm1);
|
||||
c2 = (CapabilityStatement)p.parse(strm2);
|
||||
expected = (CapabilityStatement)p.parse(strm3);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
if (c1==null || c2==null)
|
||||
Assertions.fail("Unable to read source CapabilityStatements");
|
||||
|
||||
ctxt.cacheResource(c1);
|
||||
CapabilityStatement out = csu.resolveImports(c2);
|
||||
try {
|
||||
String s1 = p.composeString(out);
|
||||
String s2 = p.composeString(expected);
|
||||
Assertions.assertEquals(s1, s2, "Merged capability statement must match expected value");
|
||||
} catch (IOException e) {
|
||||
Assertions.fail("Error serializing CapabilityStatements.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeList() {
|
||||
List l1 = new ArrayList();
|
||||
List l2 = new ArrayList();
|
||||
l1.add(makeCanonical("http://foo.bar/1", null));
|
||||
l1.add(makeCanonical("http://foo.bar/2", SHALL));
|
||||
l1.add(makeCanonical("http://foo.bar/3", SHOULD));
|
||||
l1.add(makeCanonical("http://foo.bar/4", MAY));
|
||||
l1.add(makeCanonical("http://foo.bar/5", MAY));
|
||||
l1.add(makeCanonical("http://foo.bar/6", MAY));
|
||||
|
||||
l2.add(makeCanonical("http://foo.bar/1", SHOULD));
|
||||
l2.add(makeCanonical("http://foo.bar/2", SHALL));
|
||||
l2.add(makeCanonical("http://foo.bar/3", MAY));
|
||||
l2.add(makeCanonical("http://foo.bar/4", SHOULD));
|
||||
l2.add(makeCanonical("http://foo.bar/5", null));
|
||||
l2.add(makeCanonical("http://foo.bar/7", null));
|
||||
|
||||
List l = l1.subList(0, l1.size());
|
||||
mergeIntrospect(l1, l2, "test");
|
||||
Assertions.assertTrue(l1.size() == 7);
|
||||
Assertions.assertTrue(hasConformanceElement(l1, new CanonicalType("http://foo.bar/1"), SHOULD));
|
||||
Assertions.assertTrue(hasConformanceElement(l1, new CanonicalType("http://foo.bar/2"), SHALL));
|
||||
Assertions.assertTrue(hasConformanceElement(l1, new CanonicalType("http://foo.bar/3"), SHOULD));
|
||||
Assertions.assertTrue(hasConformanceElement(l1, new CanonicalType("http://foo.bar/4"), SHOULD));
|
||||
Assertions.assertTrue(hasConformanceElement(l1, new CanonicalType("http://foo.bar/5"), MAY));
|
||||
Assertions.assertTrue(hasConformanceElement(l1, new CanonicalType("http://foo.bar/6"), MAY));
|
||||
Assertions.assertTrue(hasConformanceElement(l1, new CanonicalType("http://foo.bar/7"), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeBoolean() {
|
||||
Assertions.assertThrows(FHIRException.class,
|
||||
() -> mergeIntrospect(makeBool(true, null), makeBool(false, null), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeBool(false, null), makeBool(true, null), "test"));
|
||||
|
||||
Assertions.assertThrows(FHIRException.class,
|
||||
() -> mergeIntrospect(makeBool(true, null), makeBool(false, SHALL), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeBool(false, MAY), makeBool(true, null), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeBool(false, SHALL), makeBool(true, SHALL), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeBool(false, SHOULD), makeBool(true, SHOULD), "test"));
|
||||
|
||||
BooleanType b1 = mergeIntrospect(makeBool(false, SHALL), makeBool(true, SHOULD), "test");
|
||||
Assertions.assertEquals(b1.getValue(), false);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
b1 = mergeIntrospect(makeBool(false, SHOULD), makeBool(true, SHALL), "test");
|
||||
Assertions.assertEquals(b1.getValue(), true);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
b1 = mergeIntrospect(makeBool(false, SHALL), makeBool(true, MAY), "test");
|
||||
Assertions.assertEquals(b1.getValue(), false);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
b1 = mergeIntrospect(makeBool(false, MAY), makeBool(true, SHALL), "test");
|
||||
Assertions.assertEquals(b1.getValue(), true);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
b1 = mergeIntrospect(makeBool(true, MAY), makeBool(true, SHALL), "test");
|
||||
Assertions.assertEquals(b1.getValue(), true);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
b1 = mergeIntrospect(makeBool(false, SHOULD), makeBool(true, MAY), "test");
|
||||
Assertions.assertEquals(b1.getValue(), false);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
b1 = mergeIntrospect(makeBool(false, MAY), makeBool(true, SHOULD), "test");
|
||||
Assertions.assertEquals(b1.getValue(), true);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
b1 = mergeIntrospect(makeBool(true, MAY), makeBool(true, SHOULD), "test");
|
||||
Assertions.assertEquals(b1.getValue(), true);
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeInt() {
|
||||
Assertions.assertThrows(FHIRException.class,
|
||||
() -> mergeIntrospect(makeInt(1, null), makeInt(2, null), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeInt(2, null), makeInt(1, null), "test"));
|
||||
|
||||
Assertions.assertThrows(FHIRException.class,
|
||||
() -> mergeIntrospect(makeInt(1, null), makeInt(2, SHALL), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeInt(1, MAY), makeInt(2, null), "test"));
|
||||
|
||||
IntegerType i1 = mergeIntrospect(makeInt(1, SHALL), makeInt(2, SHOULD), "test");
|
||||
Assertions.assertEquals(i1.getValue(), 1);
|
||||
Assertions.assertEquals(i1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
i1 = mergeIntrospect(makeInt(1, SHOULD), makeInt(2, SHALL), "test");
|
||||
Assertions.assertEquals(i1.getValue(), 2);
|
||||
Assertions.assertEquals(i1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
i1 = mergeIntrospect(makeInt(2, SHOULD), makeInt(1, MAY), "test");
|
||||
Assertions.assertEquals(i1.getValue(), 2);
|
||||
Assertions.assertEquals(i1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
i1 = mergeIntrospect(makeInt(2, MAY), makeInt(1, SHOULD), "test");
|
||||
Assertions.assertEquals(i1.getValue(), 2);
|
||||
Assertions.assertEquals(i1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), MAY);
|
||||
|
||||
i1 = mergeIntrospect(makeInt(2, MAY), makeInt(1, SHALL), "test");
|
||||
Assertions.assertEquals(i1.getValue(), 1);
|
||||
Assertions.assertEquals(i1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeCode() {
|
||||
Assertions.assertThrows(FHIRException.class,
|
||||
() -> mergeIntrospect(makeCode(CR_FULLSUPPORT, null), makeCode(CR_NOTSUPPORTED, null), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeCode(CD_MULTIPLE, null), makeCode(CD_SINGLE, null), "test"));
|
||||
|
||||
Assertions.assertThrows(FHIRException.class,
|
||||
() -> mergeIntrospect(makeCode(VP_NOVERSION, null), makeCode(VP_VERSIONED, SHALL), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeCode(VP_VERSIONED, MAY), makeCode(VP_VERSIONEDUPDATE, null), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeCode(CR_NOTSUPPORTED, SHALL), makeCode(CR_MODIFIEDSINCE, SHALL), "test"));
|
||||
|
||||
Assertions.assertThrowsExactly(FHIRException.class,
|
||||
() -> mergeIntrospect(makeCode(CR_NOTMATCH, SHOULD), makeCode(CR_MODIFIEDSINCE, SHOULD), "test"));
|
||||
|
||||
Enumeration c1 = mergeIntrospect(makeCode(VP_VERSIONED, SHALL), makeCode(VP_VERSIONEDUPDATE, SHOULD), "test");
|
||||
Assertions.assertEquals(c1.getValueAsString(), VP_VERSIONED.getCode());
|
||||
Assertions.assertEquals(c1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
c1 = mergeIntrospect(makeCode(VP_VERSIONED, SHOULD), makeCode(VP_VERSIONEDUPDATE, SHALL), "test");
|
||||
Assertions.assertEquals(c1.getValueAsString(), VP_VERSIONEDUPDATE.getCode());
|
||||
Assertions.assertEquals(c1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
c1 = mergeIntrospect(makeCode(VP_VERSIONED, SHOULD), makeCode(VP_NOVERSION, MAY), "test");
|
||||
Assertions.assertEquals(c1.getValueAsString(), VP_VERSIONED.getCode());
|
||||
Assertions.assertEquals(c1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
c1 = mergeIntrospect(makeCode(VP_VERSIONED, MAY), makeCode(VP_NOVERSION, SHOULD), "test");
|
||||
Assertions.assertEquals(c1.getValueAsString(), VP_VERSIONED.getCode());
|
||||
Assertions.assertEquals(c1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), MAY);
|
||||
|
||||
c1 = mergeIntrospect(makeCode(CD_SINGLE, MAY), makeCode(CD_NOTSUPPORTED, SHALL), "test");
|
||||
Assertions.assertEquals(c1.getValueAsString(), CD_NOTSUPPORTED.getCode());
|
||||
Assertions.assertEquals(c1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMergeExpectations() {
|
||||
// null, null -> null
|
||||
BooleanType b1 = makeBool(true, null);
|
||||
csu.mergeExpectations(b1, makeBool(true, null), "SHALL");
|
||||
Assertions.assertEquals(b1.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT), false);
|
||||
|
||||
// SHALL, null -> SHALL
|
||||
b1 = makeBool(true, SHALL);
|
||||
csu.mergeExpectations(b1, makeBool(true, null), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
// SHOULD, null -> SHOULD
|
||||
b1 = makeBool(true, SHOULD);
|
||||
csu.mergeExpectations(b1, makeBool(true, null), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
// MAY, null -> MAY
|
||||
b1 = makeBool(true, MAY);
|
||||
csu.mergeExpectations(b1, makeBool(true, null), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), MAY);
|
||||
|
||||
// null, SHALL -> SHALL
|
||||
b1 = makeBool(true, null);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHALL), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
// null, SHOULD -> SHOULD
|
||||
b1 = makeBool(true, null);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHOULD), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
// null, MAY -> MAY
|
||||
b1 = makeBool(true, null);
|
||||
csu.mergeExpectations(b1, makeBool(true, MAY), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), MAY);
|
||||
|
||||
// SHALL, SHALL -> SHALL
|
||||
b1 = makeBool(true, SHALL);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHALL), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
// SHALL, SHOULD -> SHALL
|
||||
b1 = makeBool(true, SHALL);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHOULD), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
// SHALL, MAY -> SHALL
|
||||
b1 = makeBool(true, SHALL);
|
||||
csu.mergeExpectations(b1, makeBool(true, MAY), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
// SHOULD, SHALL -> SHALL
|
||||
b1 = makeBool(true, SHOULD);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHALL), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
// SHOULD, SHOULD -> SHOULD
|
||||
b1 = makeBool(true, SHOULD);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHOULD), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
// SHOULD, MAY -> SHOULD
|
||||
b1 = makeBool(true, SHOULD);
|
||||
csu.mergeExpectations(b1, makeBool(true, MAY), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
// MAY, SHALL -> SHALL
|
||||
b1 = makeBool(true, MAY);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHALL), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHALL);
|
||||
|
||||
// MAY, SHOULD -> SHOULD
|
||||
b1 = makeBool(true, MAY);
|
||||
csu.mergeExpectations(b1, makeBool(true, SHOULD), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), SHOULD);
|
||||
|
||||
// MAY, MAY -> MAY
|
||||
b1 = makeBool(true, MAY);
|
||||
csu.mergeExpectations(b1, makeBool(true, MAY), "SHALL");
|
||||
Assertions.assertEquals(b1.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType().getCode(), MAY);
|
||||
}
|
||||
|
||||
private CanonicalType makeCanonical(String url, String conformance) {
|
||||
CanonicalType c = new CanonicalType(url);
|
||||
if (conformance != null)
|
||||
c.addExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT, new CodeType(conformance));
|
||||
return c;
|
||||
}
|
||||
|
||||
private BooleanType makeBool(boolean aBool, String conformance) {
|
||||
BooleanType b = new BooleanType(aBool);
|
||||
if (conformance != null)
|
||||
b.addExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT, new CodeType(conformance));
|
||||
return b;
|
||||
}
|
||||
|
||||
private UnsignedIntType makeInt(int anInt, String conformance) {
|
||||
UnsignedIntType i = new UnsignedIntType(anInt);
|
||||
if (conformance != null)
|
||||
i.addExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT, new CodeType(conformance));
|
||||
return i;
|
||||
}
|
||||
|
||||
private Enumeration makeCode(Enumeration aCode, String conformance) {
|
||||
Enumeration c = aCode.copy();
|
||||
if (conformance != null)
|
||||
c.addExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT, new CodeType(conformance));
|
||||
return c;
|
||||
}
|
||||
|
||||
private boolean hasConformanceElement(List l, DataType d, String conformance) {
|
||||
for (Object o: l) {
|
||||
if (((DataType)o).toString().equals(d.toString())) {
|
||||
Extension e = ((DataType) o).getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT);
|
||||
if (e == null)
|
||||
return conformance==null;
|
||||
else if (e.getValueCodeType().getCode().equals(conformance))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void mergeIntrospect(List target, List imported, String context) throws FHIRException {
|
||||
try {
|
||||
Method method = CapabilityStatementUtilities.class.getDeclaredMethod("merge", List.class, List.class, String.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(csu, target, imported, context);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new Error("Bad introspection");
|
||||
} catch (InvocationTargetException e) {
|
||||
throw (FHIRException) e.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
private UnsignedIntType mergeIntrospect(UnsignedIntType targetInt, UnsignedIntType importedInt, String context) throws FHIRException {
|
||||
try {
|
||||
Method method = CapabilityStatementUtilities.class.getDeclaredMethod("merge", UnsignedIntType.class, UnsignedIntType.class, String.class);
|
||||
method.setAccessible(true);
|
||||
return (UnsignedIntType)method.invoke(csu, targetInt, importedInt, context);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new Error("Bad introspection");
|
||||
} catch (InvocationTargetException e) {
|
||||
throw (FHIRException) e.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
private BooleanType mergeIntrospect(BooleanType targetBool, BooleanType importedBool, String context) throws FHIRException {
|
||||
try {
|
||||
Method method = CapabilityStatementUtilities.class.getDeclaredMethod("merge", BooleanType.class, BooleanType.class, String.class);
|
||||
method.setAccessible(true);
|
||||
return (BooleanType)method.invoke(csu, targetBool, importedBool, context);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new Error("Bad introspection");
|
||||
} catch (InvocationTargetException e) {
|
||||
throw (FHIRException) e.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
private Enumeration mergeIntrospect(Enumeration targetCode, Enumeration importedCode, String context) throws FHIRException {
|
||||
try {
|
||||
Method method = CapabilityStatementUtilities.class.getDeclaredMethod("merge", Enumeration.class, Enumeration.class, String.class);
|
||||
method.setAccessible(true);
|
||||
return (Enumeration)method.invoke(csu, targetCode, importedCode, context);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new Error("Bad introspection");
|
||||
} catch (InvocationTargetException e) {
|
||||
throw (FHIRException) e.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
@ -69,7 +69,6 @@ import org.hl7.fhir.r5.utils.UserDataNames;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
||||
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidatorSession;
|
||||
@ -284,7 +283,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
|
||||
protected String urlRegex;
|
||||
|
||||
private boolean suppressMsg(String path, String theMessage) {
|
||||
protected boolean isSuppressedValidationMessage(String path, String theMessage) {
|
||||
if (policyAdvisor == null) {
|
||||
return false;
|
||||
} else {
|
||||
@ -293,7 +292,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean fail(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String msg = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, msg, IssueSeverity.FATAL, theMessage);
|
||||
}
|
||||
@ -313,7 +312,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hint(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg) {
|
||||
if (!thePass && doingHints() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingHints() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String message = context.formatMessage(msg);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, msg);
|
||||
}
|
||||
@ -328,7 +327,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hintInv(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, String invId) {
|
||||
if (!thePass && doingHints() && !suppressMsg(path, invId)) {
|
||||
if (!thePass && doingHints() && !isSuppressedValidationMessage(path, invId)) {
|
||||
String message = context.formatMessage(msg);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, msg).setInvId(invId);
|
||||
}
|
||||
@ -367,7 +366,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hint(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingHints() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingHints() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, theMessage);
|
||||
}
|
||||
@ -375,7 +374,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean hintPlural(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, int num, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingHints() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingHints() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessagePlural(num, theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, theMessage);
|
||||
}
|
||||
@ -388,7 +387,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean txHint(List<ValidationMessage> errors, String ruleDate, String txLink, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingHints() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingHints() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, Source.TerminologyEngine, theMessage).setTxLink(txLink);
|
||||
}
|
||||
@ -403,7 +402,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hint(List<ValidationMessage> errors, String ruleDate, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingHints() && !suppressMsg(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
if (!thePass && doingHints() && !isSuppressedValidationMessage(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
String path = toPath(pathParts);
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.INFORMATION, theMessage);
|
||||
@ -419,7 +418,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hint(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingHints() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingHints() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.INFORMATION, null);
|
||||
}
|
||||
@ -434,7 +433,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean rule(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.ERROR, theMessage);
|
||||
}
|
||||
@ -442,7 +441,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean ruleInv(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String theMessage, String invId, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.ERROR, invId).setInvId(invId);
|
||||
}
|
||||
@ -450,7 +449,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean rule(List<ValidationMessage> errors, String ruleDate, IssueType type, NodeStack stack, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(stack.getLiteralPath(), theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(stack.getLiteralPath(), theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, stack.line(), stack.col(), stack.getLiteralPath(), message, IssueSeverity.ERROR, theMessage);
|
||||
}
|
||||
@ -462,7 +461,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean rulePlural(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, int num, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessagePlural(num, theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.ERROR, theMessage);
|
||||
}
|
||||
@ -470,7 +469,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean txRule(List<ValidationMessage> errors, String ruleDate, String txLink, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
ValidationMessage vm = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, message, IssueSeverity.ERROR).setMessageId(idForMessage(theMessage, message));
|
||||
vm.setRuleDate(ruleDate);
|
||||
@ -508,7 +507,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean rule(List<ValidationMessage> errors, String ruleDate, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
String path = toPath(pathParts);
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.ERROR, theMessage);
|
||||
@ -526,7 +525,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
|
||||
|
||||
protected boolean rule(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.ERROR, theMessage);
|
||||
}
|
||||
@ -534,7 +533,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean rulePlural(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, int num, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors() && !suppressMsg(path, theMessage)) {
|
||||
if (!thePass && doingErrors() && !isSuppressedValidationMessage(path, theMessage)) {
|
||||
String message = context.formatMessagePlural(num, theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.ERROR, theMessage);
|
||||
}
|
||||
@ -600,7 +599,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warning(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity severity = IssueSeverity.WARNING;
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, severity, msg);
|
||||
@ -610,7 +609,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean warning(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String id, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity severity = IssueSeverity.WARNING;
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, severity, id);
|
||||
@ -620,7 +619,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean warningInv(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, String invId, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, invId)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, invId)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity severity = IssueSeverity.WARNING;
|
||||
String id = idForMessage(msg, nmsg);
|
||||
@ -639,7 +638,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean warningPlural(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, int num, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessagePlural(num, msg, theMessageArguments);
|
||||
IssueSeverity severity = IssueSeverity.WARNING;
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, severity, msg);
|
||||
@ -681,7 +680,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean txWarning(List<ValidationMessage> errors, String ruleDate, String txLink, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
ValidationMessage vmsg = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, nmsg, IssueSeverity.WARNING).setTxLink(txLink).setMessageId(idForMessage(msg, nmsg));
|
||||
vmsg.setRuleDate(ruleDate);
|
||||
@ -694,30 +693,23 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
|
||||
*
|
||||
* @param thePass
|
||||
* Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @param thePass Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected ValidationMessage txIssue(List<ValidationMessage> errors, String ruleDate, String txLink, int line, int col, String path, OperationOutcomeIssueComponent issue) {
|
||||
protected ValidationMessage buildValidationMessage(String txLink, int line, int col, String path, OperationOutcomeIssueComponent issue) {
|
||||
if (issue.hasLocation() && issue.getExpressionOrLocation().get(0).getValue().contains(".")) {
|
||||
path = path + dropHead(issue.getExpressionOrLocation().get(0).getValue());
|
||||
}
|
||||
IssueType code = IssueType.fromCode(issue.getCode().toCode());
|
||||
IssueSeverity severity = IssueSeverity.fromCode(issue.getSeverity().toCode());
|
||||
ValidationMessage vmsg = new ValidationMessage(Source.TerminologyEngine, code, line, col, path, issue.getDetails().getText(), severity).setTxLink(txLink);
|
||||
ValidationMessage validationMessage = new ValidationMessage(Source.TerminologyEngine, code, line, col, path, issue.getDetails().getText(), severity).setTxLink(txLink);
|
||||
if (issue.getExtensionString(ToolingExtensions.EXT_ISSUE_SERVER) != null) {
|
||||
vmsg.setServer(issue.getExtensionString(ToolingExtensions.EXT_ISSUE_SERVER).replace("local.fhir.org", "tx-dev.fhir.org"));
|
||||
validationMessage.setServer(issue.getExtensionString(ToolingExtensions.EXT_ISSUE_SERVER).replace("local.fhir.org", "tx-dev.fhir.org"));
|
||||
}
|
||||
if (issue.getExtensionString(ToolingExtensions.EXT_ISSUE_MSG_ID) != null) {
|
||||
vmsg.setMessageId(issue.getExtensionString(ToolingExtensions.EXT_ISSUE_MSG_ID));
|
||||
validationMessage.setMessageId(issue.getExtensionString(ToolingExtensions.EXT_ISSUE_MSG_ID));
|
||||
}
|
||||
|
||||
if (!suppressMsg(path, vmsg.getMessageId())) {
|
||||
errors.add(vmsg);
|
||||
}
|
||||
return vmsg;
|
||||
return validationMessage;
|
||||
}
|
||||
|
||||
private String dropHead(String value) {
|
||||
@ -732,7 +724,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean txWarningForLaterRemoval(Object location, List<ValidationMessage> errors, String ruleDate, String txLink, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
ValidationMessage vmsg = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, nmsg, IssueSeverity.WARNING).setTxLink(txLink).setMessageId(msg);
|
||||
vmsg.setRuleDate(ruleDate);
|
||||
@ -761,7 +753,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean warningOrError(boolean isError, List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && !suppressMsg(path, msg)) {
|
||||
if (!thePass && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity lvl = isError ? IssueSeverity.ERROR : IssueSeverity.WARNING;
|
||||
if (doingLevel(lvl)) {
|
||||
@ -777,7 +769,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
}
|
||||
|
||||
protected boolean hintOrError(boolean isError, List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && !suppressMsg(path, msg)) {
|
||||
if (!thePass && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity lvl = isError ? IssueSeverity.ERROR : IssueSeverity.INFORMATION;
|
||||
if (doingLevel(lvl)) {
|
||||
@ -796,7 +788,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warning(List<ValidationMessage> errors, String ruleDate, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
String path = toPath(pathParts);
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.WARNING, theMessage);
|
||||
@ -812,7 +804,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warning(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String message = context.formatMessage(msg, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.WARNING, null);
|
||||
}
|
||||
@ -827,7 +819,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warningOrHint(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, boolean warning, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && !suppressMsg(path, msg)) {
|
||||
if (!thePass && !isSuppressedValidationMessage(path, msg)) {
|
||||
String message = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity lvl = warning ? IssueSeverity.WARNING : IssueSeverity.INFORMATION;
|
||||
if (doingLevel(lvl)) {
|
||||
@ -845,7 +837,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warningHtml(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, String msg, String html) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
addValidationMessage(errors, ruleDate, type, path, msg, html, IssueSeverity.WARNING, null);
|
||||
}
|
||||
return thePass;
|
||||
@ -859,7 +851,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean warningHtml(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, path, nmsg, html, IssueSeverity.WARNING, msg);
|
||||
}
|
||||
@ -875,7 +867,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean suppressedwarning(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, IssueSeverity.INFORMATION, msg);
|
||||
}
|
||||
@ -891,7 +883,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean suppressedwarning(List<ValidationMessage> errors, String ruleDate, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(CommaSeparatedStringBuilder.join(".", pathParts), theMessage)) {
|
||||
String path = toPath(pathParts);
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, -1, -1, path, message, IssueSeverity.INFORMATION, theMessage);
|
||||
@ -946,7 +938,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean suppressedwarning(List<ValidationMessage> errors, String ruleDate, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings() && !suppressMsg(path, msg)) {
|
||||
if (!thePass && doingWarnings() && !isSuppressedValidationMessage(path, msg)) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, path, nmsg, html, IssueSeverity.INFORMATION, msg);
|
||||
}
|
||||
|
@ -38,19 +38,7 @@ import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
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.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@ -1128,7 +1116,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||
if (s == null)
|
||||
return true;
|
||||
ok = processTxIssues(errors, s, element, path, false, null, null) & ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, s, element, path, false, null, null) & ok;
|
||||
|
||||
if (s.isOk()) {
|
||||
if (s.getMessage() != null && !s.messageIsInIssues()) {
|
||||
@ -1385,7 +1373,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
if (cc.hasCoding()) {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, null, cc);
|
||||
bh.see(processTxIssues(errors, vr, element, path, false, null, null));
|
||||
bh.see(calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, null, null));
|
||||
timeTracker.tx(t, "vc " + cc.toString());
|
||||
}
|
||||
} catch (CheckCodeOnServerException e) {
|
||||
@ -1630,7 +1618,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
} else {
|
||||
checked.set(true);
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
||||
bh.see(processTxIssues(errors, vr, element, path, false, vsRef, strength));
|
||||
bh.see(calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, vsRef, strength));
|
||||
if (!vr.isOk()) {
|
||||
bindingsOk = false;
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
|
||||
@ -1725,63 +1713,126 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
// }
|
||||
// }
|
||||
|
||||
private boolean processTxIssues(List<ValidationMessage> errors, ValidationResult vr, Element element, String path, boolean ignoreCantInfer, String vsurl, BindingStrength bs) {
|
||||
boolean ok = true;
|
||||
if (vr != null) {
|
||||
for (OperationOutcomeIssueComponent iss : vr.getIssues()) {
|
||||
if (!iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-in-vs")
|
||||
&& !iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "this-code-not-in-vs")
|
||||
&& !(ignoreCantInfer || iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer"))) {
|
||||
OperationOutcomeIssueComponent i = iss.copy();
|
||||
if (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
|
||||
String msg = iss.getDetails().getText();
|
||||
boolean isHL7 = msg == null ? false : msg.contains("http://hl7.org/fhir") || msg.contains("http://terminology.hl7.org");
|
||||
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel = null;
|
||||
String notFoundNote = null;
|
||||
if (bs == null) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=null";
|
||||
} else if (bs == BindingStrength.REQUIRED && isHL7) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
notFoundNote = "error because this is a required binding to an HL7 code system";
|
||||
} else if (bs == BindingStrength.REQUIRED && unknownCodeSystemsCauseErrors) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
notFoundNote = "error because this is a required binding";
|
||||
} else if (bs == BindingStrength.REQUIRED) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=required";
|
||||
} else if (bs == BindingStrength.EXTENSIBLE) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=extensible";
|
||||
} else {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding="+bs.toCode();
|
||||
}
|
||||
if (notFoundLevel != null && i.getSeverity().isHigherThan(notFoundLevel)) { // && (vsurl != null && i.getDetails().getText().contains(vsurl))) {
|
||||
i.setSeverity(notFoundLevel);
|
||||
if (notFoundNote != null) {
|
||||
i.getDetails().setText(i.getDetails().getText()+" ("+notFoundNote+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (baseOptions.isDisplayWarningMode() && i.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR && i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "invalid-display")) {
|
||||
i.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
|
||||
}
|
||||
var vmsg = txIssue(errors, null, vr.getTxLink(), element.line(), element.col(), path, i);
|
||||
if (vmsg.isError()) {
|
||||
ok = false;
|
||||
/**
|
||||
* For each issue in the validationResult, determine first if it should be ignored, and if not, calculate its severity
|
||||
* and add it to the errors list.
|
||||
*
|
||||
* @param errors a list of validation messages that are errors
|
||||
* @param validationResult the validation result containing terminology issues to be evaluated
|
||||
* @param element the element being validated
|
||||
* @param path the path of the element being validated
|
||||
* @param ignoreCantInfer if true, the element will be ignored
|
||||
* @param vsurl the value set url
|
||||
* @param bindingStrength the binding strength of the code/codeable concept
|
||||
* @return true if no errors were added to the errors list, false otherwise
|
||||
*/
|
||||
private boolean calculateSeverityForTxIssuesAndUpdateErrors(List<ValidationMessage> errors, ValidationResult validationResult, Element element, String path, boolean ignoreCantInfer, String vsurl, BindingStrength bindingStrength) {
|
||||
if (validationResult == null) {
|
||||
return true;
|
||||
}
|
||||
boolean noErrorsFound = true;
|
||||
for (OperationOutcomeIssueComponent issue : validationResult.getIssues()) {
|
||||
if (!isIgnoredTxIssueType(issue, ignoreCantInfer)) {
|
||||
OperationOutcomeIssueComponent issueWithCalculatedSeverity = getTxIssueWithCalculatedSeverity(issue, bindingStrength);
|
||||
var validationMessage = buildValidationMessage(validationResult.getTxLink(), element.line(), element.col(), path, issueWithCalculatedSeverity);
|
||||
if (!isSuppressedValidationMessage(path, validationMessage.getMessageId())) {
|
||||
errors.add(validationMessage);
|
||||
if (validationMessage.isError()) {
|
||||
noErrorsFound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
return noErrorsFound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the issueComponent should not be included when evaluating if terminology issues contain errors.
|
||||
* <p/>
|
||||
* The following tx-issue-types are ignored:
|
||||
* <ul>
|
||||
* <li>not-in-vs</li>
|
||||
* <li>this-code-not-in-vs</li>
|
||||
* <li>cannot-infer</li>
|
||||
* </ul>
|
||||
* Note that cannot-infer is only ignored if ignoreCantInfer is true.
|
||||
*
|
||||
* @param issueComponent the issue
|
||||
* @param ignoreCantInfer if true, ignore
|
||||
* @return true if the issue should be ignored when evaluating if terminology issues contain errors, false otherwise
|
||||
*/
|
||||
private boolean isIgnoredTxIssueType(OperationOutcomeIssueComponent issueComponent, boolean ignoreCantInfer) {
|
||||
if (issueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-in-vs")) {
|
||||
return true;
|
||||
}
|
||||
if (issueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "this-code-not-in-vs")) {
|
||||
return true;
|
||||
}
|
||||
if (issueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer") || ignoreCantInfer) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a new issue from the passed issueComponent with appropriate severity.
|
||||
* <p/>
|
||||
* If the issueComponent has a tx-issue-type of "not-found", the returned value will have an appropriate severity
|
||||
* based on bindingStrength. The issueComponent text will also be updated to include the reason for error level
|
||||
* severity.
|
||||
* <p/>
|
||||
* If the issueComponent has a tx-issue-type of "invalid-display" the returned value will have an appropriate severity
|
||||
* based on displayWarningMode.
|
||||
* <p/>
|
||||
* All other issues will be returned unchanged.
|
||||
* @param issueComponent the issue component
|
||||
* @param bindingStrength the binding strength of the code/codeable concept
|
||||
* @return the new issue component with appropriate severity
|
||||
*/
|
||||
private OperationOutcomeIssueComponent getTxIssueWithCalculatedSeverity(OperationOutcomeIssueComponent issueComponent, BindingStrength bindingStrength) {
|
||||
OperationOutcomeIssueComponent newIssueComponent = issueComponent.copy();
|
||||
if (newIssueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
|
||||
String text = issueComponent.getDetails().getText();
|
||||
boolean isHL7 = text == null ? false : text.contains("http://hl7.org/fhir") || text.contains("http://terminology.hl7.org");
|
||||
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel = null;
|
||||
String notFoundNote = null;
|
||||
if (bindingStrength == null) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=null";
|
||||
} else if (bindingStrength == BindingStrength.REQUIRED && isHL7) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
notFoundNote = "error because this is a required binding to an HL7 code system";
|
||||
} else if (bindingStrength == BindingStrength.REQUIRED && unknownCodeSystemsCauseErrors) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR;
|
||||
notFoundNote = "error because this is a required binding";
|
||||
} else if (bindingStrength == BindingStrength.REQUIRED) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=required";
|
||||
} else if (bindingStrength == BindingStrength.EXTENSIBLE) {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding=extensible";
|
||||
} else {
|
||||
notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING;
|
||||
notFoundNote = null; // "binding="+bs.toCode();
|
||||
}
|
||||
if (notFoundLevel != null && newIssueComponent.getSeverity().isHigherThan(notFoundLevel)) { // && (vsurl != null && i.getDetails().getText().contains(vsurl))) {
|
||||
newIssueComponent.setSeverity(notFoundLevel);
|
||||
if (notFoundNote != null) {
|
||||
newIssueComponent.getDetails().setText(newIssueComponent.getDetails().getText() + " (" + notFoundNote + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newIssueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "invalid-display") && baseOptions.isDisplayWarningMode() && newIssueComponent.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR) {
|
||||
newIssueComponent.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
|
||||
}
|
||||
return newIssueComponent;
|
||||
}
|
||||
|
||||
public boolean checkBindings(List<ValidationMessage> errors, String path, Element element, NodeStack stack, ValueSet valueset, Coding nextCoding) {
|
||||
boolean ok = true;
|
||||
if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem(), baseOptions.getFhirVersion())) {
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, nextCoding);
|
||||
ok = processTxIssues(errors, vr, element, path, false, null, null) && ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, null, null) && ok;
|
||||
|
||||
if (vr.getSeverity() != null && !vr.messageIsInIssues()) {
|
||||
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
|
||||
@ -1912,7 +1963,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
if (strength == BindingStrength.REQUIRED) {
|
||||
removeTrackedMessagesForLocation(errors, element, path);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, false, vsRef, strength) && ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, vsRef, strength) && ok;
|
||||
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||
if (vr != null && !vr.isOk()) {
|
||||
if (vr.IsNoService())
|
||||
@ -2057,7 +2108,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
||||
ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
timeTracker.tx(t, "vc "+cc.toString());
|
||||
if (!vr.isOk()) {
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||
@ -2096,7 +2147,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, c);
|
||||
ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||
if (!vr.isOk()) {
|
||||
@ -2127,7 +2178,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, value, baseOptions);
|
||||
ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok;
|
||||
timeTracker.tx(t, "vc "+value);
|
||||
if (!vr.isOk()) {
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||
@ -2262,7 +2313,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
checked.set(true);
|
||||
vr = checkCodeOnServer(stack, valueset, c);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, strength == BindingStrength.EXTENSIBLE, vsRef, strength) && ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, strength == BindingStrength.EXTENSIBLE, vsRef, strength) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||
if (strength == BindingStrength.REQUIRED) {
|
||||
@ -3083,7 +3134,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
}
|
||||
if (type.equals("integer") || type.equals("unsignedInt") || type.equals("positiveInt")) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isInteger(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_VALID, e.primitiveValue())) {
|
||||
Integer v = new Integer(e.getValue()).intValue();
|
||||
Integer v = Integer.valueOf(e.getValue());
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueIntegerType() || !context.getMaxValueIntegerType().hasValue() || (context.getMaxValueIntegerType().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueIntegerType() ? context.getMaxValueIntegerType() : "")) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueIntegerType() || !context.getMinValueIntegerType().hasValue() || (context.getMinValueIntegerType().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueIntegerType() ? context.getMinValueIntegerType() : "")) && ok;
|
||||
if (type.equals("unsignedInt"))
|
||||
@ -3096,7 +3147,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
}
|
||||
if (type.equals("integer64")) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isLong(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER64_VALID, e.primitiveValue())) {
|
||||
Long v = new Long(e.getValue()).longValue();
|
||||
Long v = Long.valueOf(e.getValue());
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueInteger64Type() || !context.getMaxValueInteger64Type().hasValue() || (context.getMaxValueInteger64Type().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueInteger64Type() ? context.getMaxValueInteger64Type() : "")) && ok;
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueInteger64Type() || !context.getMinValueInteger64Type().hasValue() || (context.getMinValueInteger64Type().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueInteger64Type() ? context.getMinValueInteger64Type() : "")) && ok;
|
||||
if (type.equals("unsignedInt"))
|
||||
@ -3737,7 +3788,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||
}
|
||||
vr = checkCodeOnServer(stack, vs, value, options);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet(), binding.getStrength()) && ok;
|
||||
ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet(), binding.getStrength()) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+value+"");
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user