Merge remote-tracking branch 'origin/master'

This commit is contained in:
Grahame Grieve 2024-12-08 19:59:45 +03:00
commit 62fe79bff2
19 changed files with 1471 additions and 224 deletions

View File

@ -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());

View File

@ -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));
}
}

View File

@ -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
*/

View File

@ -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));
}
}

View File

@ -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
*/

View File

@ -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));
}
}

View File

@ -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);
}
}
/**

View File

@ -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));
}
}

View File

@ -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);
}
}
/**

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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
*

View File

@ -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) {

View File

@ -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));
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -188,12 +188,6 @@
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- Apache POI -->
<dependency>
<groupId>org.apache.poi</groupId>