This commit is contained in:
Grahame Grieve 2021-11-29 16:11:23 +11:00
commit 93d266b363
69 changed files with 1287 additions and 1005 deletions

28
.github/workflows/bidi-checker.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: BIDI CHECK
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ master ]
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
bidi_checker_job:
runs-on: ubuntu-latest
name: Check for bidi unicode characters in repo
steps:
# Checkout the repo code. IMPORTANT, this step is needed to populate the directory defined by GITHUB_WORKSPACE
- name: Checkout repo
uses: actions/checkout@v1
id: checkout
# Run the check for bidi characters.
- name: Check for bidi characters
id: bidi_check
uses: HL7/bidi-checker-action@v1.5
- name: Get the output time
run: echo "The time was ${{ steps.bidi_check.outputs.time }}"

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -46,6 +46,7 @@ import org.hl7.fhir.dstu2.model.ValueSet.ConceptDefinitionComponent;
import org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu2.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.dstu2.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.dstu2.utils.validation.IResourceValidator;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;

View File

@ -59,6 +59,7 @@ import org.hl7.fhir.dstu2.model.ValueSet;
import org.hl7.fhir.dstu2.terminologies.ValueSetExpansionCache;
import org.hl7.fhir.dstu2.utils.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.dstu2.utils.client.FHIRToolingClient;
import org.hl7.fhir.dstu2.utils.validation.IResourceValidator;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.CSFileInputStream;

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.dstu2.utils;
package org.hl7.fhir.dstu2.utils.validation;
/*
Copyright (c) 2011+, HL7, Inc.
@ -34,6 +34,9 @@ package org.hl7.fhir.dstu2.utils;
import java.util.List;
import org.hl7.fhir.dstu2.model.StructureDefinition;
import org.hl7.fhir.dstu2.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.dstu2.utils.validation.constants.CheckDisplayOption;
import org.hl7.fhir.dstu2.utils.validation.constants.IdStatus;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -42,29 +45,6 @@ import com.google.gson.JsonObject;
public interface IResourceValidator {
/**
* whether the validator should enforce best practice guidelines
* as defined by various HL7 committees
*
*
* @author Grahame Grieve
*
*/
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}
/**
* how much to check displays for coded elements
* @return
@ -77,10 +57,6 @@ public interface IResourceValidator {
*/
void setCheckDisplay(CheckDisplayOption checkDisplay);
enum IdStatus {
OPTIONAL, REQUIRED, PROHIBITED
}
/**
* whether the resource must have an id or not (depends on context)
*
@ -93,39 +69,26 @@ public interface IResourceValidator {
BestPracticeWarningLevel getBasePracticeWarningLevel();
void setBestPracticeWarningLevel(BestPracticeWarningLevel value);
/**
* Given a DOM element, return a list of errors in the resource
*
* @param errors
* @param elem
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, Element element) throws Exception;
/**
* Given a JSON Object, return a list of errors in the resource
*
* @param errors
* @param elem
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, JsonObject object) throws Exception;
/**
* Given a DOM element, return a list of errors in the resource
*
* @param errors
* @param elem
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
List<ValidationMessage> validate(Element element) throws Exception;
/**
* Given a DOM element, return a list of errors in the resource
*
* @param errors
* @param elem
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
List<ValidationMessage> validate(JsonObject object) throws Exception;
@ -133,10 +96,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile (by logical identifier)
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, Element element, String profile) throws Exception;
@ -144,10 +103,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile (by logical identifier)
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
*/
List<ValidationMessage> validate(Element element, String profile) throws Exception;
@ -155,10 +110,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile (by logical identifier)
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
*/
List<ValidationMessage> validate(JsonObject object, StructureDefinition profile) throws Exception;
@ -166,10 +117,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile (by logical identifier)
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
*/
List<ValidationMessage> validate(JsonObject object, String profile) throws Exception;
@ -177,10 +124,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, Element element, StructureDefinition profile) throws Exception;
@ -188,10 +131,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, JsonObject object, StructureDefinition profile) throws Exception;
@ -199,10 +138,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, JsonObject object, String profile) throws Exception;
@ -210,10 +145,6 @@ public interface IResourceValidator {
/**
* Given a DOM element, return a list of errors in the resource
* with regard to the specified profile
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
List<ValidationMessage> validate(Element element, StructureDefinition profile) throws Exception;
@ -221,18 +152,12 @@ public interface IResourceValidator {
/**
* Given a DOM document, return a list of errors in the resource
*
* @param errors
* @param elem
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, Document document) throws Exception;
/**
* Given a DOM document, return a list of errors in the resource
*
* @param errors
* @param elem
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
List<ValidationMessage> validate(Document document) throws Exception;
@ -240,10 +165,6 @@ public interface IResourceValidator {
/**
* Given a DOM document, return a list of errors in the resource
* with regard to the specified profile (by logical identifier)
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, Document document, String profile) throws Exception;
@ -251,10 +172,6 @@ public interface IResourceValidator {
/**
* Given a DOM document, return a list of errors in the resource
* with regard to the specified profile (by logical identifier)
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails, or the profile can't be found (not if the resource is invalid)
*/
List<ValidationMessage> validate(Document document, String profile) throws Exception;
@ -262,10 +179,6 @@ public interface IResourceValidator {
/**
* Given a DOM document, return a list of errors in the resource
* with regard to the specified profile
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
void validate(List<ValidationMessage> errors, Document document, StructureDefinition profile) throws Exception;
@ -273,10 +186,6 @@ public interface IResourceValidator {
/**
* Given a DOM document, return a list of errors in the resource
* with regard to the specified profile
*
* @param errors
* @param element
* @param profile
* @- if the underlying infrastructure fails (not if the resource is invalid)
*/
List<ValidationMessage> validate(Document document, StructureDefinition profile) throws Exception;

View File

@ -0,0 +1,12 @@
package org.hl7.fhir.dstu2.utils.validation.constants;
/**
* whether the validator should enforce best practice guidelines
* as defined by various HL7 committees
*/
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}

View File

@ -0,0 +1,9 @@
package org.hl7.fhir.dstu2.utils.validation.constants;
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}

View File

@ -0,0 +1,7 @@
package org.hl7.fhir.dstu2.utils.validation.constants;
public enum IdStatus {
OPTIONAL,
REQUIRED,
PROHIBITED
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -52,7 +52,7 @@ import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
import org.hl7.fhir.dstu3.utils.IResourceValidator;
import org.hl7.fhir.dstu3.utils.validation.IResourceValidator;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;

View File

@ -80,7 +80,7 @@ import org.hl7.fhir.dstu3.model.StructureMap.StructureMapStructureComponent;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.dstu3.terminologies.ValueSetExpansionCache;
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
import org.hl7.fhir.dstu3.utils.IResourceValidator;
import org.hl7.fhir.dstu3.utils.validation.IResourceValidator;
import org.hl7.fhir.dstu3.utils.NarrativeGenerator;
import org.hl7.fhir.dstu3.utils.client.FHIRToolingClient;
import org.hl7.fhir.exceptions.DefinitionException;

View File

@ -206,14 +206,19 @@ public class FhirRequestBuilder {
public <T extends Resource> ResourceRequest<T> execute() throws IOException {
formatHeaders(httpRequest, resourceFormat, headers);
Response response = getHttpClient().newCall(httpRequest.build()).execute();
final Request request = httpRequest.build();
log(request.method(), request.url().toString(), request.headers(), request.body() != null ? request.body().toString().getBytes() : null);
Response response = getHttpClient().newCall(request).execute();
T resource = unmarshalReference(response, resourceFormat);
return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers()));
}
public Bundle executeAsBatch() throws IOException {
formatHeaders(httpRequest, resourceFormat, null);
Response response = getHttpClient().newCall(httpRequest.build()).execute();
final Request request = httpRequest.build();
log(request.method(), request.url().toString(), request.headers(), request.body() != null ? request.body().toString().getBytes() : null);
Response response = getHttpClient().newCall(request).execute();
return unmarshalFeed(response, resourceFormat);
}
@ -302,6 +307,26 @@ public class FhirRequestBuilder {
}
}
/**
* Logs the given {@link Request}, using the current {@link ToolingClientLogger}. If the current
* {@link FhirRequestBuilder#logger} is null, no action is taken.
*
* @param method HTTP request method
* @param url request URL
* @param requestHeaders {@link Headers} for request
* @param requestBody Byte array request
*/
protected void log(String method, String url, Headers requestHeaders, byte[] requestBody) {
if (logger != null) {
List<String> headerList = new ArrayList<>(Collections.emptyList());
Map<String, List<String>> headerMap = requestHeaders.toMultimap();
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
logger.logRequest(method, url, headerList, requestBody);
}
}
/**
* Logs the given {@link Response}, using the current {@link ToolingClientLogger}. If the current
* {@link FhirRequestBuilder#logger} is null, no action is taken.

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.dstu3.utils;
package org.hl7.fhir.dstu3.utils.validation;
/*
Copyright (c) 2011+, HL7, Inc.
@ -30,21 +30,20 @@ package org.hl7.fhir.dstu3.utils;
*/
import com.google.gson.JsonObject;
import org.hl7.fhir.dstu3.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.dstu3.utils.ValidationProfileSet;
import org.hl7.fhir.dstu3.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.dstu3.utils.validation.constants.CheckDisplayOption;
import org.hl7.fhir.dstu3.utils.validation.constants.IdStatus;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.hl7.fhir.dstu3.elementmodel.Element;
import org.hl7.fhir.dstu3.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import com.google.gson.JsonObject;
/**
* Interface to the instance validator. This takes a resource, in one of many forms, and
* checks whether it is valid
@ -54,49 +53,6 @@ import com.google.gson.JsonObject;
*/
public interface IResourceValidator {
public enum ReferenceValidationPolicy {
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
public boolean checkExists() {
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
}
public boolean checkType() {
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
}
public boolean checkValid() {
return this == CHECK_VALID;
}
}
public interface IValidatorResourceFetcher {
Element fetch(Object appContext, String url) throws FHIRFormatError, DefinitionException, IOException, FHIRException;
ReferenceValidationPolicy validationPolicy(Object appContext, String path, String url);
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
}
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}
enum IdStatus {
OPTIONAL, REQUIRED, PROHIBITED
}
/**
* how much to check displays for coded elements
* @return
@ -124,21 +80,24 @@ public interface IResourceValidator {
IValidatorResourceFetcher getFetcher();
IResourceValidator setFetcher(IValidatorResourceFetcher value);
IValidationPolicyAdvisor getPolicyAdvisor();
IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor);
boolean isNoBindingMsgSuppressed();
IResourceValidator setNoBindingMsgSuppressed(boolean noBindingMsgSuppressed);
public boolean isNoInvariantChecks();
public IResourceValidator setNoInvariantChecks(boolean value) ;
boolean isNoInvariantChecks();
IResourceValidator setNoInvariantChecks(boolean value) ;
public boolean isNoTerminologyChecks();
public IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
boolean isNoTerminologyChecks();
IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
/**
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning
* @return
*/
public boolean isErrorForUnknownProfiles();
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
boolean isErrorForUnknownProfiles();
void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
/**
* Validate suite

View File

@ -0,0 +1,21 @@
package org.hl7.fhir.dstu3.utils.validation;
import org.hl7.fhir.dstu3.elementmodel.Element;
import org.hl7.fhir.dstu3.utils.validation.constants.ReferenceValidationPolicy;
public interface IValidationPolicyAdvisor {
ReferenceValidationPolicy policyForReference(IResourceValidator validator,
Object appContext,
String path,
String url);
ReferenceValidationPolicy policyForContained(IResourceValidator validator,
Object appContext,
String containerType,
String containerId,
Element.SpecialElement containingResourceType,
String path,
String url);
}

View File

@ -0,0 +1,13 @@
package org.hl7.fhir.dstu3.utils.validation;
import org.hl7.fhir.dstu3.elementmodel.Element;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import java.io.IOException;
public interface IValidatorResourceFetcher {
Element fetch(Object appContext, String url) throws IOException, FHIRException;
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
}

View File

@ -0,0 +1,8 @@
package org.hl7.fhir.dstu3.utils.validation.constants;
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}

View File

@ -0,0 +1,9 @@
package org.hl7.fhir.dstu3.utils.validation.constants;
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}

View File

@ -0,0 +1,7 @@
package org.hl7.fhir.dstu3.utils.validation.constants;
public enum IdStatus {
OPTIONAL,
REQUIRED,
PROHIBITED
}

View File

@ -0,0 +1,21 @@
package org.hl7.fhir.dstu3.utils.validation.constants;
public enum ReferenceValidationPolicy {
IGNORE,
CHECK_TYPE_IF_EXISTS,
CHECK_EXISTS,
CHECK_EXISTS_AND_TYPE,
CHECK_VALID;
public boolean checkExists() {
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
}
public boolean checkType() {
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
}
public boolean checkValid() {
return this == CHECK_VALID;
}
}

View File

@ -0,0 +1,101 @@
package org.hl7.fhir.dstu3.utils.client.network;
import okhttp3.*;
import org.hl7.fhir.dstu3.formats.IParser;
import org.hl7.fhir.utilities.ToolingClientLogger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.AdditionalMatchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.ArgumentMatchers;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
@ExtendWith(MockitoExtension.class)
public class FhirRequestBuilderTests {
private static final String DUMMY_URL = "https://some-url.com/";
Request mockRequest = new Request.Builder()
.url(DUMMY_URL)
.build();
final String RESPONSE_BODY_STRING = "{}";
Response response = new Response.Builder()
.request(mockRequest)
.protocol(Protocol.HTTP_2)
.code(200) // status code
.message("")
.body(ResponseBody.create(RESPONSE_BODY_STRING,
MediaType.get("application/json; charset=utf-8")
))
.addHeader("Content-Type", "")
.build();
final Request.Builder requestBuilder = new Request.Builder()
.url(DUMMY_URL);
final FhirRequestBuilder fhirRequestBuilder = Mockito.spy(new FhirRequestBuilder(requestBuilder));
@Mock
OkHttpClient client;
@Mock
Call mockCall;
@Mock
ToolingClientLogger logger;
@BeforeEach
public void beforeEach() {
Mockito.doReturn(client).when(fhirRequestBuilder).getHttpClient();
fhirRequestBuilder.withLogger(logger);
}
@Nested
class RequestLoggingTests {
@BeforeEach
public void beforeEach() throws IOException {
Mockito.doReturn(response).when(mockCall).execute();
Mockito.doReturn(mockCall).when(client).newCall(ArgumentMatchers.any());
Mockito.doReturn(null).when(fhirRequestBuilder).unmarshalReference(ArgumentMatchers.any(), ArgumentMatchers.isNull());
}
@Test
public void testExecuteLogging() throws IOException {
fhirRequestBuilder.execute();
Mockito.verify(logger).logRequest(ArgumentMatchers.eq("GET"), ArgumentMatchers.eq(DUMMY_URL), ArgumentMatchers.anyList(), ArgumentMatchers.isNull());
}
@Test
public void testExecuteBatchLogging() throws IOException {
fhirRequestBuilder.executeAsBatch();
Mockito.verify(logger).logRequest(ArgumentMatchers.eq("GET"), ArgumentMatchers.eq(DUMMY_URL), ArgumentMatchers.anyList(), ArgumentMatchers.isNull());
}
}
@Test
public void testUnmarshallReferenceLogging() {
IParser parser = Mockito.mock(IParser.class);
Mockito.doReturn(parser).when(fhirRequestBuilder).getParser(ArgumentMatchers.eq("json"));
fhirRequestBuilder.unmarshalReference(response, "json");
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()));
}
@Test
public void testUnmarshallFeedLogging() {
fhirRequestBuilder.unmarshalFeed(response, "application/json");
Mockito.verify(logger).logResponse(ArgumentMatchers.eq("200"), ArgumentMatchers.anyList(), AdditionalMatchers.aryEq(RESPONSE_BODY_STRING.getBytes()));
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -33,7 +33,6 @@ package org.hl7.fhir.r4.context;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.fhir.ucum.UcumService;
@ -58,8 +57,7 @@ import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.utils.INarrativeGenerator;
import org.hl7.fhir.r4.utils.IResourceValidator;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
import org.hl7.fhir.utilities.TranslationServices;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationOptions;

View File

@ -75,7 +75,7 @@ import org.hl7.fhir.r4.model.StructureMap.StructureMapModelMode;
import org.hl7.fhir.r4.model.StructureMap.StructureMapStructureComponent;
import org.hl7.fhir.r4.terminologies.TerminologyClient;
import org.hl7.fhir.r4.utils.INarrativeGenerator;
import org.hl7.fhir.r4.utils.IResourceValidator;
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
import org.hl7.fhir.r4.utils.NarrativeGenerator;
import org.hl7.fhir.utilities.CSFileInputStream;
import org.hl7.fhir.utilities.Utilities;

View File

@ -115,6 +115,7 @@ import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.Utilities;

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r4.utils;
package org.hl7.fhir.r4.utils.validation;
/*
Copyright (c) 2011+, HL7, Inc.
@ -29,18 +29,17 @@ package org.hl7.fhir.r4.utils;
*/
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r4.elementmodel.Element;
import org.hl7.fhir.r4.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.utils.ValidationProfileSet;
import org.hl7.fhir.r4.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.r4.utils.validation.constants.CheckDisplayOption;
import org.hl7.fhir.r4.utils.validation.constants.IdStatus;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import com.google.gson.JsonObject;
@ -54,69 +53,21 @@ import com.google.gson.JsonObject;
*/
public interface IResourceValidator {
public enum ReferenceValidationPolicy {
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
public boolean checkExists() {
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
}
public boolean checkType() {
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
}
public boolean checkValid() {
return this == CHECK_VALID;
}
}
public interface IValidatorResourceFetcher {
Element fetch(Object appContext, String url) throws FHIRFormatError, DefinitionException, FHIRException, IOException;
ReferenceValidationPolicy validationPolicy(Object appContext, String path, String url);
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
}
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}
enum IdStatus {
OPTIONAL, REQUIRED, PROHIBITED
}
/**
* how much to check displays for coded elements
* @return
*/
CheckDisplayOption getCheckDisplay();
void setCheckDisplay(CheckDisplayOption checkDisplay);
/**
* whether the resource must have an id or not (depends on context)
*
* @return
*/
IdStatus getResourceIdRule();
void setResourceIdRule(IdStatus resourceIdRule);
/**
* whether the validator should enforce best practice guidelines
* as defined by various HL7 committees
*
*/
BestPracticeWarningLevel getBestPracticeWarningLevel();
IResourceValidator setBestPracticeWarningLevel(BestPracticeWarningLevel value);
@ -124,27 +75,29 @@ public interface IResourceValidator {
IValidatorResourceFetcher getFetcher();
IResourceValidator setFetcher(IValidatorResourceFetcher value);
IValidationPolicyAdvisor getPolicyAdvisor();
IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor);
boolean isNoBindingMsgSuppressed();
IResourceValidator setNoBindingMsgSuppressed(boolean noBindingMsgSuppressed);
public boolean isNoInvariantChecks();
public IResourceValidator setNoInvariantChecks(boolean value) ;
boolean isNoInvariantChecks();
IResourceValidator setNoInvariantChecks(boolean value) ;
public boolean isNoTerminologyChecks();
public IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
boolean isNoTerminologyChecks();
IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
public boolean isNoExtensibleWarnings();
public IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
boolean isNoExtensibleWarnings();
IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
/**
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning
* @return
*/
public boolean isErrorForUnknownProfiles();
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
boolean isErrorForUnknownProfiles();
void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
public String getValidationLanguage();
public void setValidationLanguage(String value);
String getValidationLanguage();
void setValidationLanguage(String value);
/**
* Validate suite
@ -194,5 +147,4 @@ public interface IResourceValidator {
org.hl7.fhir.r4.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object, String profile) throws FHIRException;
org.hl7.fhir.r4.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object, StructureDefinition profile) throws FHIRException;
}

View File

@ -0,0 +1,21 @@
package org.hl7.fhir.r4.utils.validation;
import org.hl7.fhir.r4.elementmodel.Element;
import org.hl7.fhir.r4.utils.validation.constants.ReferenceValidationPolicy;
public interface IValidationPolicyAdvisor {
ReferenceValidationPolicy policyForReference(IResourceValidator validator,
Object appContext,
String path,
String url);
ReferenceValidationPolicy policyForContained(IResourceValidator validator,
Object appContext,
String containerType,
String containerId,
Element.SpecialElement containingResourceType,
String path,
String url);
}

View File

@ -0,0 +1,11 @@
package org.hl7.fhir.r4.utils.validation;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.elementmodel.Element;
import java.io.IOException;
public interface IValidatorResourceFetcher {
Element fetch(Object appContext, String url) throws FHIRException, IOException;
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
}

View File

@ -0,0 +1,8 @@
package org.hl7.fhir.r4.utils.validation.constants;
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}

View File

@ -0,0 +1,9 @@
package org.hl7.fhir.r4.utils.validation.constants;
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}

View File

@ -0,0 +1,7 @@
package org.hl7.fhir.r4.utils.validation.constants;
public enum IdStatus {
OPTIONAL,
REQUIRED,
PROHIBITED
}

View File

@ -0,0 +1,21 @@
package org.hl7.fhir.r4.utils.validation.constants;
public enum ReferenceValidationPolicy {
IGNORE,
CHECK_TYPE_IF_EXISTS,
CHECK_EXISTS,
CHECK_EXISTS_AND_TYPE,
CHECK_VALID;
public boolean checkExists() {
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
}
public boolean checkType() {
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
}
public boolean checkValid() {
return this == CHECK_VALID;
}
}

View File

@ -22,7 +22,7 @@ import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.test.utils.TestingUtilities;
import org.hl7.fhir.r4.utils.FHIRPathEngine;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r4.utils.IResourceValidator;
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
import org.hl7.fhir.r4.utils.NarrativeGenerator;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -89,12 +89,13 @@ public class HTMLClientLogger extends BaseLogger implements ToolingClientLogger
if (DEBUG) {
System.out.println(" txlog resp: " +outcome+" "+present(body));
}
req = false;
if (file == null)
return;
if (!req) {
System.out.println("Record Response without request");
}
req = false;
file.println("<pre>");
file.println(outcome);
for (String s : headers)

View File

@ -44,7 +44,6 @@ import org.fhir.ucum.UcumService;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.context.IWorkerContext.CodingValidationRequest;
import org.hl7.fhir.r5.context.TerminologyCache.CacheToken;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.ParserType;
@ -64,7 +63,7 @@ import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.TranslationServices;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;

View File

@ -54,9 +54,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory;
import org.hl7.fhir.r5.context.SimpleWorkerContext.PackageResourceLoader;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.ParserType;
@ -76,7 +74,7 @@ import org.hl7.fhir.r5.model.StructureMap;
import org.hl7.fhir.r5.model.StructureMap.StructureMapModelMode;
import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent;
import org.hl7.fhir.r5.terminologies.TerminologyClient;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.CSFileInputStream;
import org.hl7.fhir.utilities.TextFile;
@ -85,15 +83,12 @@ import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import com.google.gson.JsonObject;
import ca.uhn.fhir.parser.DataFormatException;
/*

View File

@ -9,7 +9,7 @@ import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import java.util.ArrayList;

View File

@ -0,0 +1,29 @@
package org.hl7.fhir.r5.utils.validation;
public class BundleValidationRule {
private String rule;
private String profile;
private boolean checked;
public BundleValidationRule(String rule, String profile) {
super();
this.rule = rule;
this.profile = profile;
}
public String getRule() {
return rule;
}
public String getProfile() {
return profile;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
}

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r5.utils;
package org.hl7.fhir.r5.utils.validation;
/*
Copyright (c) 2011+, HL7, Inc.
@ -30,26 +30,18 @@ package org.hl7.fhir.r5.utils;
*/
import com.google.gson.JsonObject;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption;
import org.hl7.fhir.r5.utils.validation.constants.IdStatus;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Locale;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import com.google.gson.JsonObject;
/**
* Interface to the instance validator. This takes a resource, in one of many forms, and
@ -60,124 +52,21 @@ import com.google.gson.JsonObject;
*/
public interface IResourceValidator {
public class BundleValidationRule {
private String rule;
private String profile;
private boolean checked;
public BundleValidationRule(String rule, String profile) {
super();
this.rule = rule;
this.profile = profile;
}
public String getRule() {
return rule;
}
public String getProfile() {
return profile;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
}
public enum ReferenceValidationPolicy {
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
public boolean checkExists() {
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID || this == CHECK_TYPE_IF_EXISTS;
}
public boolean checkType() {
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
}
public boolean checkValid() {
return this == CHECK_VALID;
}
}
public interface IValidationProfileUsageTracker {
void recordProfileUsage(StructureDefinition profile, Object appContext, Element element);
}
public interface IValidatorResourceFetcher {
Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRFormatError, DefinitionException, FHIRException, IOException;
ReferenceValidationPolicy validationPolicy(IResourceValidator validator, Object appContext, String path, String url);
boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException;
byte[] fetchRaw(IResourceValidator validator, String url) throws MalformedURLException, IOException; // for attachment checking
IValidatorResourceFetcher setLocale(Locale locale);
/**
* this is used when the validator encounters a reference to a structure definition, value set or code system at some random URL reference
* while validating.
*
* Added in v5.2.2. return null to leave functionality as it was before then.
*
* @param primitiveValue
* @return an R5 version of the resource
* @throws URISyntaxException
*/
CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException;
/**
* Whether to try calling fetchCanonicalResource for this reference (not whether it will succeed - just throw an exception from fetchCanonicalResource if it doesn't resolve. This is a policy thing.
*
* Added in v5.2.2. return false to leave functionality as it was before then.
*
* @param url
* @return
*/
boolean fetchesCanonicalResource(IResourceValidator validator, String url);
}
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}
enum IdStatus {
OPTIONAL, REQUIRED, PROHIBITED
}
/**
* how much to check displays for coded elements
* @return
*/
CheckDisplayOption getCheckDisplay();
void setCheckDisplay(CheckDisplayOption checkDisplay);
/**
* whether the resource must have an id or not (depends on context)
*
* @return
*/
IdStatus getResourceIdRule();
void setResourceIdRule(IdStatus resourceIdRule);
/**
* whether the validator should enforce best practice guidelines
* as defined by various HL7 committees
*
*/
BestPracticeWarningLevel getBestPracticeWarningLevel();
IResourceValidator setBestPracticeWarningLevel(BestPracticeWarningLevel value);
@ -185,48 +74,46 @@ public interface IResourceValidator {
IValidatorResourceFetcher getFetcher();
IResourceValidator setFetcher(IValidatorResourceFetcher value);
IValidationPolicyAdvisor getPolicyAdvisor();
IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor);
IValidationProfileUsageTracker getTracker();
IResourceValidator setTracker(IValidationProfileUsageTracker value);
boolean isNoBindingMsgSuppressed();
IResourceValidator setNoBindingMsgSuppressed(boolean noBindingMsgSuppressed);
public boolean isNoInvariantChecks();
public IResourceValidator setNoInvariantChecks(boolean value) ;
boolean isNoInvariantChecks();
IResourceValidator setNoInvariantChecks(boolean value) ;
public boolean isWantInvariantInMessage();
public IResourceValidator setWantInvariantInMessage(boolean wantInvariantInMessage);
boolean isWantInvariantInMessage();
IResourceValidator setWantInvariantInMessage(boolean wantInvariantInMessage);
public boolean isNoTerminologyChecks();
public IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
boolean isNoTerminologyChecks();
IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
public boolean isNoExtensibleWarnings();
public IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
boolean isNoExtensibleWarnings();
IResourceValidator setNoExtensibleWarnings(boolean noExtensibleWarnings);
public boolean isNoUnicodeBiDiControlChars();
public void setNoUnicodeBiDiControlChars(boolean noUnicodeBiDiControlChars);
boolean isNoUnicodeBiDiControlChars();
void setNoUnicodeBiDiControlChars(boolean noUnicodeBiDiControlChars);
/**
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning
* @return
*/
public boolean isErrorForUnknownProfiles();
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
boolean isErrorForUnknownProfiles();
void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
public boolean isShowMessagesFromReferences();
public void setShowMessagesFromReferences(boolean value);
boolean isShowMessagesFromReferences();
void setShowMessagesFromReferences(boolean value);
/**
* this is used internally in the publishing stack to ensure that everything is water tight, but
* this check is not necessary or appropriate at run time when the validator is hosted in HAPI
* @return
*/
public boolean isWantCheckSnapshotUnchanged();
public void setWantCheckSnapshotUnchanged(boolean wantCheckSnapshotUnchanged);
//FIXME: don't need that, gets never used?
// public String getValidationLanguage();
// public void setValidationLanguage(String value);
boolean isWantCheckSnapshotUnchanged();
void setWantCheckSnapshotUnchanged(boolean wantCheckSnapshotUnchanged);
/**
* It's common to see references such as Patient/234234 - these usually mean a reference to a Patient resource.
@ -235,27 +122,28 @@ public interface IResourceValidator {
*
* @return
*/
public boolean isAssumeValidRestReferences();
public void setAssumeValidRestReferences(boolean value);
boolean isAssumeValidRestReferences();
void setAssumeValidRestReferences(boolean value);
/**
* if this is true, the validator will accept extensions and references to example.org and acme.com as
* valid, on the basis that they are understood to be references to content that could exist in priniple but can't in practice
*/
public boolean isAllowExamples();
public void setAllowExamples(boolean value) ;
boolean isAllowExamples();
void setAllowExamples(boolean value) ;
boolean isNoCheckAggregation();
void setNoCheckAggregation(boolean value);
public boolean isNoCheckAggregation();
public void setNoCheckAggregation(boolean value);
/**
* CrumbTrail - whether the validator creates hints to
* @return
*/
public boolean isCrumbTrails();
public void setCrumbTrails(boolean crumbTrails);
boolean isCrumbTrails();
void setCrumbTrails(boolean crumbTrails);
public boolean isValidateValueSetCodesOnTxServer();
public void setValidateValueSetCodesOnTxServer(boolean value);
boolean isValidateValueSetCodesOnTxServer();
void setValidateValueSetCodesOnTxServer(boolean value);
/**
* Bundle validation rules allow for requesting particular entries in a bundle get validated against particular profiles
@ -264,7 +152,7 @@ public interface IResourceValidator {
*
* @return
*/
public List<BundleValidationRule> getBundleValidationRules();
List<BundleValidationRule> getBundleValidationRules();
/**
* Validate suite

View File

@ -0,0 +1,41 @@
package org.hl7.fhir.r5.utils.validation;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
public interface IValidationPolicyAdvisor {
/**
*
* @param validator
* @param appContext What was originally provided from the app for it's context
* @param path Path that led us to this resource.
* @param url Url of the profile the container resource is being validated against.
* @return {@link ReferenceValidationPolicy}
*/
ReferenceValidationPolicy policyForReference(IResourceValidator validator,
Object appContext,
String path,
String url);
/**
* //TODO pass through the actual containing Element as opposed to the type, id
* @param validator
* @param appContext What was originally provided from the app for it's context
* @param containerType Type of the resources that contains the resource being validated
* @param containerId Id of the resources that contains the resource being validated
* @param containingResourceType Type of the resource that will be validated (BUNDLE_ENTRY, BUNDLE_OUTCOME, CONTAINED_RESOURCE, PARAMETER)
* @param path Path that led us to this resource.
* @param url Url of the profile the container resource is being validated against.
* @return {@link ReferenceValidationPolicy}
*/
ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator,
Object appContext,
String containerType,
String containerId,
Element.SpecialElement containingResourceType,
String path,
String url);
}

View File

@ -0,0 +1,8 @@
package org.hl7.fhir.r5.utils.validation;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.StructureDefinition;
public interface IValidationProfileUsageTracker {
void recordProfileUsage(StructureDefinition profile, Object appContext, Element element);
}

View File

@ -0,0 +1,41 @@
package org.hl7.fhir.r5.utils.validation;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.CanonicalResource;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Locale;
public interface IValidatorResourceFetcher {
Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRException, IOException;
boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException;
byte[] fetchRaw(IResourceValidator validator, String url) throws IOException; // for attachment checking
IValidatorResourceFetcher setLocale(Locale locale);
/**
* this is used when the validator encounters a reference to a structure definition, value set or code system at some random URL reference
* while validating.
* <p>
* Added in v5.2.2. return null to leave functionality as it was before then.
*
* @return an R5 version of the resource
* @throws URISyntaxException
*/
CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException;
/**
* Whether to try calling fetchCanonicalResource for this reference (not whether it will succeed - just throw an exception from fetchCanonicalResource if it doesn't resolve. This is a policy thing.
* <p>
* Added in v5.2.2. return false to leave functionality as it was before then.
*
* @param url
* @return
*/
boolean fetchesCanonicalResource(IResourceValidator validator, String url);
}

View File

@ -0,0 +1,8 @@
package org.hl7.fhir.r5.utils.validation.constants;
public enum BestPracticeWarningLevel {
Ignore,
Hint,
Warning,
Error
}

View File

@ -0,0 +1,9 @@
package org.hl7.fhir.r5.utils.validation.constants;
public enum CheckDisplayOption {
Ignore,
Check,
CheckCaseAndSpace,
CheckCase,
CheckSpace
}

View File

@ -0,0 +1,19 @@
package org.hl7.fhir.r5.utils.validation.constants;
public enum ContainedReferenceValidationPolicy {
IGNORE,
CHECK_TYPE,
CHECK_VALID;
public boolean ignore() {
return this == IGNORE;
}
public boolean checkType() {
return this == CHECK_TYPE || this == CHECK_VALID;
}
public boolean checkValid() {
return this == CHECK_VALID;
}
}

View File

@ -0,0 +1,7 @@
package org.hl7.fhir.r5.utils.validation.constants;
public enum IdStatus {
OPTIONAL,
REQUIRED,
PROHIBITED
}

View File

@ -0,0 +1,25 @@
package org.hl7.fhir.r5.utils.validation.constants;
public enum ReferenceValidationPolicy {
IGNORE,
CHECK_TYPE_IF_EXISTS,
CHECK_EXISTS,
CHECK_EXISTS_AND_TYPE,
CHECK_VALID;
public boolean ignore() {
return this == IGNORE;
}
public boolean checkExists() {
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID || this == CHECK_TYPE_IF_EXISTS;
}
public boolean checkType() {
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
}
public boolean checkValid() {
return this == CHECK_VALID;
}
}

View File

@ -1,61 +1,27 @@
package org.hl7.fhir.r5.test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.renderers.RendererFactory;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.ToolsVersion;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
public class ParsingTests {

View File

@ -39,7 +39,7 @@ import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.CommonPackages;

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.Random;
import static org.junit.jupiter.api.Assertions.*;
@ -126,27 +127,34 @@ class UtilitiesTest {
public static final int BIG_NEG = Utilities.ONE_MB * -1;
private static final String buildMeasureLimitMessage(int size, String contains) {
return MessageFormat.format("\"{0}\" should contain \"{1}\"", size, contains);
}
//TODO we've witnessed at least one intermittent failure of this test. It could be refactored to run several times to
// trigger edge cases more often now that it provides better feedback.
@Test
@DisplayName("Test size bounds on file size utility.")
void describeSizeTest() {
Assertions.assertAll("GB Measure Limits",
() -> assertTrue(Utilities.describeSize(GB_MEASURE_JUST_OVER).contains(Utilities.GB)),
() -> assertTrue(Utilities.describeSize(GB_MEASURE_EXACT).contains(Utilities.MB)),
() -> assertTrue(Utilities.describeSize(GB_MEASURE_JUST_UNDER).contains(Utilities.MB))
() -> assertTrue(Utilities.describeSize(GB_MEASURE_JUST_OVER).contains(Utilities.GB), buildMeasureLimitMessage(GB_MEASURE_JUST_OVER, Utilities.GB)),
() -> assertTrue(Utilities.describeSize(GB_MEASURE_EXACT).contains(Utilities.MB), buildMeasureLimitMessage(GB_MEASURE_EXACT, Utilities.MB)),
() -> assertTrue(Utilities.describeSize(GB_MEASURE_JUST_UNDER).contains(Utilities.MB), buildMeasureLimitMessage(GB_MEASURE_JUST_UNDER, Utilities.MB))
);
Assertions.assertAll("MB Measure Limits",
() -> assertTrue(Utilities.describeSize(MB_MEASURE_JUST_OVER).contains(Utilities.MB)),
() -> assertTrue(Utilities.describeSize(MB_MEASURE_EXACT).contains(Utilities.KB)),
() -> assertTrue(Utilities.describeSize(MB_MEASURE_JUST_UNDER).contains(Utilities.KB))
() -> assertTrue(Utilities.describeSize(MB_MEASURE_JUST_OVER).contains(Utilities.MB), buildMeasureLimitMessage(MB_MEASURE_JUST_OVER, Utilities.MB)),
() -> assertTrue(Utilities.describeSize(MB_MEASURE_EXACT).contains(Utilities.KB), buildMeasureLimitMessage(MB_MEASURE_EXACT, Utilities.KB)),
() -> assertTrue(Utilities.describeSize(MB_MEASURE_JUST_UNDER).contains(Utilities.KB), buildMeasureLimitMessage(MB_MEASURE_JUST_UNDER, Utilities.KB))
);
Assertions.assertAll("KB Measure Limits",
() -> assertTrue(Utilities.describeSize(KB_MEASURE_JUST_OVER).contains(Utilities.KB)),
() -> assertTrue(Utilities.describeSize(KB_MEASURE_EXACT).contains(Utilities.BT)),
() -> assertTrue(Utilities.describeSize(KB_MEASURE_JUST_UNDER).contains(Utilities.BT))
() -> assertTrue(Utilities.describeSize(KB_MEASURE_JUST_OVER).contains(Utilities.KB), buildMeasureLimitMessage(KB_MEASURE_JUST_OVER, Utilities.KB)),
() -> assertTrue(Utilities.describeSize(KB_MEASURE_EXACT).contains(Utilities.BT), buildMeasureLimitMessage(KB_MEASURE_EXACT, Utilities.BT)),
() -> assertTrue(Utilities.describeSize(KB_MEASURE_JUST_UNDER).contains(Utilities.BT), buildMeasureLimitMessage(KB_MEASURE_JUST_UNDER, Utilities.BT))
);
Assertions.assertAll("BT Measure Limits",
() -> assertTrue(Utilities.describeSize(BT_MEASURE).contains(Utilities.BT)),
() -> assertTrue(Utilities.describeSize(EMPTY).contains(Utilities.BT))
() -> assertTrue(Utilities.describeSize(BT_MEASURE).contains(Utilities.BT), buildMeasureLimitMessage(BT_MEASURE, Utilities.BT)),
() -> assertTrue(Utilities.describeSize(EMPTY).contains(Utilities.BT), buildMeasureLimitMessage(EMPTY, Utilities.BT))
);
Assertions.assertThrows(IllegalArgumentException.class, () -> Utilities.describeSize(BIG_NEG));
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -1,13 +1,5 @@
package org.hl7.fhir.validation;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
/*
Copyright (c) 2011+, HL7, Inc.
@ -38,47 +30,10 @@ import java.util.HashMap;
*/
/*
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.
*/
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
@ -88,11 +43,16 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.validation.BaseValidator.TrackedLocationRelatedMessage;
import org.hl7.fhir.validation.instance.utils.IndexedElement;
public class BaseValidator {
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class BaseValidator {
public class TrackedLocationRelatedMessage {
private Object location;
private ValidationMessage vmsg;
@ -107,8 +67,7 @@ public class BaseValidator {
public ValidationMessage getVmsg() {
return vmsg;
}
}
}
public class ValidationControl {
private boolean allowed;

View File

@ -34,9 +34,6 @@ package org.hl7.fhir.validation;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.hl7.fhir.convertors.conv10_50.VersionConvertor_10_50;
import org.hl7.fhir.convertors.conv14_50.VersionConvertor_14_50;
import org.hl7.fhir.convertors.conv30_50.VersionConvertor_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
@ -69,9 +66,9 @@ import org.hl7.fhir.r5.model.FhirPublication;
import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.IResourceValidator.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.IResourceValidator.CheckDisplayOption;
import org.hl7.fhir.r5.utils.IResourceValidator.IdStatus;
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption;
import org.hl7.fhir.r5.utils.validation.constants.IdStatus;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;

View File

@ -3,9 +3,6 @@ package org.hl7.fhir.validation;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.hl7.fhir.convertors.conv10_50.VersionConvertor_10_50;
import org.hl7.fhir.convertors.conv14_50.VersionConvertor_14_50;
import org.hl7.fhir.convertors.conv30_50.VersionConvertor_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
@ -35,10 +32,13 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.IResourceValidator.*;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.validation.constants.*;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.*;
import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult;
@ -57,7 +57,6 @@ import org.xml.sax.SAXException;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
/*
@ -131,7 +130,7 @@ POSSIBILITY OF SUCH DAMAGE.
* @author Grahame Grieve
*/
@Accessors(chain = true)
public class ValidationEngine implements IValidatorResourceFetcher, IPackageInstaller {
public class ValidationEngine implements IValidatorResourceFetcher, IValidationPolicyAdvisor, IPackageInstaller {
@Getter @Setter private SimpleWorkerContext context;
@Getter @Setter private Map<String, byte[]> binaries = new HashMap<>();
@ -146,6 +145,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
@Getter @Setter private PrintWriter mapLog;
@Getter @Setter private boolean debug = false;
@Getter @Setter private IValidatorResourceFetcher fetcher;
@Getter @Setter private IValidationPolicyAdvisor policyAdvisor;
@Getter @Setter private ICanonicalResourceLocator locator;
@Getter @Setter private boolean assumeValidRestReferences;
@Getter @Setter private boolean noExtensibleBindingMessages;
@ -730,22 +730,43 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
}
@Override
public ReferenceValidationPolicy validationPolicy(IResourceValidator validator, Object appContext, String path, String url) {
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
Resource resource = context.fetchResource(StructureDefinition.class, url);
if (resource != null) {
return ReferenceValidationPolicy.CHECK_VALID;
}
if (!(url.contains("hl7.org") || url.contains("fhir.org"))) {
return ReferenceValidationPolicy.IGNORE;
} else if (fetcher != null) {
return fetcher.validationPolicy(validator, appContext, path, url);
} else if (policyAdvisor != null) {
return policyAdvisor.policyForReference(validator, appContext, path, url);
} else {
return ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE;
}
}
@Override
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException {
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator,
Object appContext,
String containerType,
String containerId,
Element.SpecialElement containingResourceType,
String path,
String url) {
Resource resource = context.fetchResource(StructureDefinition.class, url);
if (resource != null) {
return ContainedReferenceValidationPolicy.CHECK_VALID;
}
if (!(url.contains("hl7.org") || url.contains("fhir.org"))) {
return ContainedReferenceValidationPolicy.IGNORE;
} else if (policyAdvisor != null) {
return policyAdvisor.policyForContained(validator, appContext, containerType, containerId, containingResourceType, path, url);
} else {
return ContainedReferenceValidationPolicy.CHECK_TYPE;
}
}
@Override
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws FHIRException {
if (!url.startsWith("http://") && !url.startsWith("https://")) { // ignore these
return true;
}

View File

@ -7,7 +7,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.cli.utils.EngineMode;

View File

@ -8,9 +8,11 @@ import org.hl7.fhir.r5.context.IWorkerContext.ICanonicalResourceLocator;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.terminologies.TerminologyClient;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.IResourceValidator.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy;
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.constants.ContainedReferenceValidationPolicy;
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
@ -28,7 +30,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, ICanonicalResourceLocator {
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IValidationPolicyAdvisor, ICanonicalResourceLocator {
List<String> mappingsUris = new ArrayList<>();
private FilesystemPackageCacheManager pcm;
@ -51,10 +53,24 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IC
}
@Override
public ReferenceValidationPolicy validationPolicy(IResourceValidator validator, Object appContext, String path, String url) {
public ReferenceValidationPolicy policyForReference(IResourceValidator validator,
Object appContext,
String path,
String url) {
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS;
}
@Override
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator,
Object appContext,
String containerType,
String containerId,
Element.SpecialElement containingResourceType,
String path,
String url) {
return ContainedReferenceValidationPolicy.CHECK_TYPE;
}
@Override
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException {
if (!Utilities.isAbsoluteUrl(url)) {

View File

@ -1,7 +1,6 @@
package org.hl7.fhir.validation.cli.utils;
import org.apache.http.auth.AUTH;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.cli.model.CliContext;

View File

@ -47,8 +47,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.codec.binary.Base64InputStream;
import org.apache.commons.lang3.NotImplementedException;
@ -135,9 +133,10 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.*;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.validation.constants.*;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.SIDUtilities;
import org.hl7.fhir.utilities.UnicodeUtilities;
@ -174,8 +173,6 @@ import org.w3c.dom.Document;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import javax.annotation.Nonnull;
/**
* Thinking of using this in a java program? Don't!
@ -381,6 +378,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private Map<String, Element> fetchCache = new HashMap<>();
private HashMap<Element, ResourceValidationTracker> resourceTracker = new HashMap<>();
private IValidatorResourceFetcher fetcher;
private IValidationPolicyAdvisor policyAdvisor;
long time = 0;
private IEvaluationContext externalHostServices;
private boolean noExtensibleWarnings;
@ -464,6 +462,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return this;
}
@Override
public IValidationPolicyAdvisor getPolicyAdvisor() {
return policyAdvisor;
}
@Override
public IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor) {
this.policyAdvisor = advisor;
return this;
}
public IValidationProfileUsageTracker getTracker() {
return this.tracker;
}
@ -2114,7 +2123,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
if (!found) {
if (type.equals("canonical")) {
ReferenceValidationPolicy rp = fetcher.validationPolicy(this, appContext, path, url);
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, appContext, path, url);
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
} else {
@ -2131,7 +2140,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
} else {
if (type.equals("canonical")) {
ReferenceValidationPolicy rp = fetcher.validationPolicy(this, appContext, path, url);
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, appContext, path, url);
if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) {
try {
Resource r = fetcher.fetchCanonicalResource(this, url);
@ -2690,14 +2699,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
checkFixedValue(errors, path + ".denominator", focus.getNamedChild("denominator"), fixed.getDenominator(), fixedSource, "denominator", focus, pattern);
}
private void checkReference(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition container, String parentType, NodeStack stack) throws FHIRException {
private void checkReference(ValidatorHostContext hostContext,
List<ValidationMessage> errors,
String path,
Element element,
StructureDefinition profile,
ElementDefinition container,
String parentType,
NodeStack stack) throws FHIRException {
Reference reference = ObjectConverter.readAsReference(element);
String ref = reference.getReference();
if (Utilities.noString(ref)) {
if (!path.contains("element.pattern")) { // this business rule doesn't apply to patterns
if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) {
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY);
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path,
!Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY);
}
}
return;
@ -2718,7 +2735,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
refType = "bundled";
}
}
ReferenceValidationPolicy pol = refType.equals("contained") || refType.equals("bundled") ? ReferenceValidationPolicy.CHECK_VALID : fetcher == null ? ReferenceValidationPolicy.IGNORE : fetcher.validationPolicy(this, hostContext.getAppContext(), path, ref);
ReferenceValidationPolicy pol;
if (refType.equals("contained") || refType.equals("bundled")) {
pol = ReferenceValidationPolicy.CHECK_VALID;
} else {
if (policyAdvisor == null) pol = ReferenceValidationPolicy.IGNORE;
else pol = policyAdvisor.policyForReference(this, hostContext.getAppContext(), path, ref);
}
if (pol.checkExists()) {
if (we == null) {
@ -2745,7 +2768,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
}
boolean ok = (allowExamples && (ref.contains("example.org") || ref.contains("acme.com"))) || (we != null || pol == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS);
boolean ok = (allowExamples && (ref.contains("example.org") || ref.contains("acme.com")))
|| (we != null || pol == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS);
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok, I18nConstants.REFERENCE_REF_CANTRESOLVE, ref);
}
@ -2767,22 +2791,26 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
boolean matchingResource = false;
for (CanonicalType target : containerType.getTargetProfile()) {
StructureDefinition sd = resolveProfile(profile, target.asStringValue());
if (rule(errors, IssueType.NOTFOUND, element.line(), element.col(), path, sd != null, I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, target.asStringValue())) {
if (rule(errors, IssueType.NOTFOUND, element.line(), element.col(), path, sd != null,
I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, target.asStringValue())) {
if (("http://hl7.org/fhir/StructureDefinition/" + sd.getType()).equals(tu)) {
matchingResource = true;
break;
}
}
}
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, matchingResource, I18nConstants.REFERENCE_REF_WRONGTARGET, reference.getType(), container.getType("Reference").getTargetProfile());
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, matchingResource,
I18nConstants.REFERENCE_REF_WRONGTARGET, reference.getType(), container.getType("Reference").getTargetProfile());
}
// the type has to match the actual
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ft == null || ft.equals(reference.getType()), I18nConstants.REFERENCE_REF_BADTARGETTYPE, reference.getType(), ft);
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path,
ft == null || ft.equals(reference.getType()), I18nConstants.REFERENCE_REF_BADTARGETTYPE, reference.getType(), ft);
}
if (we != null && pol.checkType()) {
if (warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ft != null, I18nConstants.REFERENCE_REF_NOTYPE)) {
if (warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ft != null,
I18nConstants.REFERENCE_REF_NOTYPE)) {
// we validate as much as we can. First, can we infer a type from the profile?
boolean ok = false;
TypeRefComponent type = getReferenceTypeRef(container.getType());
@ -2791,7 +2819,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
List<StructureDefinition> profiles = new ArrayList<>();
for (UriType u : type.getTargetProfile()) {
StructureDefinition sd = resolveProfile(profile, u.getValue());
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, sd != null, I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, u.getValue())) {
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, sd != null,
I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, u.getValue())) {
types.add(sd.getType());
if (ft.equals(sd.getType())) {
ok = true;
@ -2800,14 +2829,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
if (!pol.checkValid()) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() > 0, I18nConstants.REFERENCE_REF_CANTMATCHTYPE, ref, StringUtils.join("; ", type.getTargetProfile()));
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() > 0,
I18nConstants.REFERENCE_REF_CANTMATCHTYPE, ref, StringUtils.join("; ", type.getTargetProfile()));
} else {
Map<StructureDefinition, List<ValidationMessage>> badProfiles = new HashMap<StructureDefinition, List<ValidationMessage>>();
Map<StructureDefinition, List<ValidationMessage>> goodProfiles = new HashMap<StructureDefinition, List<ValidationMessage>>();
Map<StructureDefinition, List<ValidationMessage>> badProfiles = new HashMap<>();
Map<StructureDefinition, List<ValidationMessage>> goodProfiles = new HashMap<>();
int goodCount = 0;
for (StructureDefinition pr : profiles) {
List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
validateResource(we.hostContext(hostContext, pr), profileErrors, we.getResource(), we.getFocus(), pr, IdStatus.OPTIONAL, we.getStack().resetIds());
validateResource(we.hostContext(hostContext, pr), profileErrors, we.getResource(), we.getFocus(), pr,
IdStatus.OPTIONAL, we.getStack().resetIds());
if (!hasErrors(profileErrors)) {
goodCount++;
goodProfiles.put(pr, profileErrors);
@ -2827,14 +2858,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else if (goodProfiles.size() == 0) {
if (!isShowMessagesFromReferences()) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, areAllBaseProfiles(profiles), I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, areAllBaseProfiles(profiles),
I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
for (StructureDefinition sd : badProfiles.keySet()) {
slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, false,
context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()),
errorSummaryForSlicingAsHtml(badProfiles.get(sd)), errorSummaryForSlicingAsText(badProfiles.get(sd)));
}
} else {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() == 1, I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() == 1,
I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
for (List<ValidationMessage> messages : badProfiles.values()) {
for (ValidationMessage vm : messages) {
if (!errors.contains(vm)) {
@ -2845,13 +2878,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
} else {
if (!isShowMessagesFromReferences()) {
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false,
I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
for (StructureDefinition sd : badProfiles.keySet()) {
slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, false, context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()),
slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false,
false, context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()),
errorSummaryForSlicingAsHtml(badProfiles.get(sd)), errorSummaryForSlicingAsText(badProfiles.get(sd)));
}
} else {
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false,
I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
for (List<ValidationMessage> messages : goodProfiles.values()) {
for (ValidationMessage vm : messages) {
if (!errors.contains(vm)) {
@ -2862,7 +2898,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
}
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok, I18nConstants.REFERENCE_REF_BADTARGETTYPE, ft, types.toString());
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok,
I18nConstants.REFERENCE_REF_BADTARGETTYPE, ft, types.toString());
}
if (type.hasAggregation() && !noCheckAggregation) {
boolean modeOk = false;
@ -2876,7 +2913,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
else if (mode.getValue().equals(AggregationMode.REFERENCED) && (refType.equals("bundled") || refType.equals("remote")))
modeOk = true;
}
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, modeOk, I18nConstants.REFERENCE_REF_AGGREGATION, refType, b.toString());
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, modeOk,
I18nConstants.REFERENCE_REF_AGGREGATION, refType, b.toString());
}
}
}
@ -2905,7 +2943,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
sdF = sdF.hasBaseDefinition() ? context.fetchResource(StructureDefinition.class, sdF.getBaseDefinition()) : null;
}
}
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, types.isEmpty() || ok, I18nConstants.REFERENCE_REF_BADTARGETTYPE2, ft, ref, types);
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, types.isEmpty() || ok,
I18nConstants.REFERENCE_REF_BADTARGETTYPE2, ft, ref, types);
}
if (pol == ReferenceValidationPolicy.CHECK_VALID) {
@ -4349,84 +4388,108 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
private void validateContains(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, ElementDefinition child, ElementDefinition context, Element resource, Element element, NodeStack stack, IdStatus idstatus) throws FHIRException {
private void validateContains(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path,
ElementDefinition child, ElementDefinition context, Element resource,
Element element, NodeStack stack, IdStatus idstatus, StructureDefinition parentProfile) throws FHIRException {
SpecialElement special = element.getSpecial();
ContainedReferenceValidationPolicy containedValidationPolicy = getPolicyAdvisor() == null ?
ContainedReferenceValidationPolicy.CHECK_VALID : getPolicyAdvisor().policyForContained(this,
hostContext, context.fhirType(), context.getId(), special, path, parentProfile.getUrl());
if (containedValidationPolicy.ignore()) {
return;
}
String resourceName = element.getType();
TypeRefComponent trr = null;
TypeRefComponent typeForResource = null;
CommaSeparatedStringBuilder bt = new CommaSeparatedStringBuilder();
for (TypeRefComponent tr : child.getType()) {
bt.append(tr.getCode());
if (tr.getCode().equals("Resource") || tr.getCode().equals(resourceName) ) {
trr = tr;
// Iterate through all possible types
for (TypeRefComponent type : child.getType()) {
bt.append(type.getCode());
if (type.getCode().equals("Resource") || type.getCode().equals(resourceName) ) {
typeForResource = type;
break;
}
}
stack.qualifyPath(".ofType("+resourceName+")");
if (trr == null) {
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName, bt.toString());
} else if (isValidResourceType(resourceName, trr)) {
// special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise
ValidatorHostContext hc = null;
if (element.getSpecial() == SpecialElement.BUNDLE_ENTRY || element.getSpecial() == SpecialElement.BUNDLE_OUTCOME || element.getSpecial() == SpecialElement.PARAMETER) {
resource = element;
hc = hostContext.forEntry(element);
} else {
hc = hostContext.forContained(element);
}
stack.resetIds();
if (element.getSpecial() != null) {
switch (element.getSpecial()) {
case BUNDLE_ENTRY:
idstatus = IdStatus.OPTIONAL;
break;
case BUNDLE_OUTCOME:
idstatus = IdStatus.OPTIONAL;
break;
case CONTAINED:
stack.setContained(true);
idstatus = IdStatus.REQUIRED;
break;
case PARAMETER:
idstatus = IdStatus.OPTIONAL;
break;
default:
break;
if (typeForResource == null) {
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(),
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName, bt.toString());
} else if (isValidResourceType(resourceName, typeForResource)) {
if (containedValidationPolicy.checkValid()) {
// special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise
ValidatorHostContext hc = null;
if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.PARAMETER) {
resource = element;
hc = hostContext.forEntry(element);
} else {
hc = hostContext.forContained(element);
}
}
if (trr.getProfile().size() == 1) {
long t = System.nanoTime();
StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, trr.getProfile().get(0).asStringValue());
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
stack.resetIds();
if (special != null) {
switch (special) {
case BUNDLE_ENTRY:
case BUNDLE_OUTCOME:
case PARAMETER:
idstatus = IdStatus.OPTIONAL;
break;
case CONTAINED:
stack.setContained(true);
idstatus = IdStatus.REQUIRED;
break;
default:
break;
}
}
} else if (trr.getProfile().size() == 0) {
long t = System.nanoTime();
StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + resourceName);
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
if (typeForResource.getProfile().size() == 1) {
long t = System.nanoTime();
StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, typeForResource.getProfile().get(0).asStringValue());
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else if (typeForResource.getProfile().isEmpty()) {
long t = System.nanoTime();
StructureDefinition profile = this.context.fetchResource(StructureDefinition.class,
"http://hl7.org/fhir/StructureDefinition/" + resourceName);
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (CanonicalType u : typeForResource.getProfile()) {
b.append(u.asStringValue());
}
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, typeForResource.getCode(), b.toString());
}
} else {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (CanonicalType u : trr.getProfile()) {
b.append(u.asStringValue());
}
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, trr.getCode(), b.toString());
}
} else {
List<String> types = new ArrayList<>();
for (UriType u : trr.getProfile()) {
for (UriType u : typeForResource.getProfile()) {
StructureDefinition sd = this.context.fetchResource(StructureDefinition.class, u.getValue());
if (sd != null && !types.contains(sd.getType())) {
types.add(sd.getType());
}
}
if (types.size() == 1) {
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE2, resourceName, types.get(0));
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(),
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE2, resourceName, types.get(0));
} else {
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE3, resourceName, types);
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(),
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE3, resourceName, types);
}
}
}
@ -4590,7 +4653,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), false, I18nConstants.EXTENSION_PROF_TYPE, profile.getUrl(), type, stype);
}
}
//
// Excluding reference is a kludge to get around versioning issues
if (checkDefn.getType().get(0).hasProfile()) {
for (CanonicalType p : checkDefn.getType().get(0).getProfile()) {
@ -4717,7 +4780,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
} else if (type.equals("Resource") || isResource(type)) {
validateContains(hostContext, errors, ei.getPath(), checkDefn, definition, resource, ei.getElement(), localStack, idStatusForEntry(element, ei)); // if
validateContains(hostContext, errors, ei.getPath(), checkDefn, definition, resource, ei.getElement(),
localStack, idStatusForEntry(element, ei), profile); // if
elementValidated = true;
// (str.matches(".*([.,/])work\\1$"))
} else if (Utilities.isAbsoluteUrl(type)) {
@ -5288,18 +5352,24 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
/*
* The actual base entry point for internal use (re-entrant)
*/
private void validateResource(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, IdStatus idstatus, NodeStack stack) throws FHIRException {
private void validateResource(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element resource,
Element element, StructureDefinition defn, IdStatus idstatus, NodeStack stack) throws FHIRException {
// check here if we call validation policy here, and then change it to the new interface
assert stack != null;
assert resource != null;
boolean ok = true;
String resourceName = element.getType(); // todo: consider namespace...?
if (defn == null) {
long t = System.nanoTime();
defn = element.getProperty().getStructure();
if (defn == null)
defn = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + resourceName);
timeTracker.sd(t);
ok = rule(errors, IssueType.INVALID, element.line(), element.col(), stack.addToLiteralPath(resourceName), defn != null, I18nConstants.VALIDATION_VAL_PROFILE_NODEFINITION, resourceName);
//check exists
ok = rule(errors, IssueType.INVALID, element.line(), element.col(), stack.addToLiteralPath(resourceName),
defn != null, I18nConstants.VALIDATION_VAL_PROFILE_NODEFINITION, resourceName);
}
// special case: we have a bundle, and the profile is not for a bundle. We'll try the first entry instead
@ -5308,13 +5378,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (first != null && typeMatchesDefn(first.getElement().getType(), defn)) {
element = first.getElement();
stack = first;
resourceName = element.getType();
idstatus = IdStatus.OPTIONAL; // why?
}
// todo: validate everything in this bundle.
}
ok = rule(errors, IssueType.INVALID, -1, -1, stack.getLiteralPath(), typeMatchesDefn(resourceName, defn), I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE, defn.getType(), resourceName, defn.getName());
if (ok) {
if (idstatus == IdStatus.REQUIRED && (element.getNamedChild(ID) == null)) {
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_MISSING);
@ -5328,6 +5395,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
rule(errors, IssueType.INVALID, eid.line(), eid.col(), ns.getLiteralPath(), FormatUtilities.isValidId(eid.primitiveValue()), I18nConstants.RESOURCE_RES_ID_MALFORMED);
}
}
// validate
start(hostContext, errors, element, element, defn, stack); // root is both definition and type
}
}

View File

@ -35,7 +35,7 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.SimpleWorkerContext.IValidatorFactory;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
public class InstanceValidatorFactory implements IValidatorFactory {

View File

@ -14,7 +14,7 @@ import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.r5.model.Enumerations.FHIRVersion;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
@ -369,7 +369,8 @@ public class BundleValidator extends BaseValidator{
if (ref != null && !Utilities.noString(reference) && !reference.startsWith("#")) {
Element target = resolveInBundle(entries, reference, fullUrl, type, id);
rule(errors, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), target != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, reference, name);
rule(errors, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), target != null,
I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, reference, name);
}
}

View File

@ -37,11 +37,12 @@ import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.StructureMap;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.test.utils.TestingUtilities;
import org.hl7.fhir.r4.utils.IResourceValidator;
import org.hl7.fhir.r4.utils.IResourceValidator.IValidatorResourceFetcher;
import org.hl7.fhir.r4.utils.IResourceValidator.ReferenceValidationPolicy;
import org.hl7.fhir.r4.utils.validation.IResourceValidator;
import org.hl7.fhir.r4.utils.validation.IValidatorResourceFetcher;
import org.hl7.fhir.r4.utils.validation.constants.ReferenceValidationPolicy;
import org.hl7.fhir.r4.utils.StructureMapUtilities;
import org.hl7.fhir.r4.utils.StructureMapUtilities.ITransformerServices;
import org.hl7.fhir.r4.utils.validation.IValidationPolicyAdvisor;
import org.hl7.fhir.utilities.IniFile;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
@ -62,7 +63,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
@Disabled
public class R3R4ConversionTests implements ITransformerServices, IValidatorResourceFetcher {
public class R3R4ConversionTests implements ITransformerServices, IValidatorResourceFetcher, IValidationPolicyAdvisor {
private static final boolean SAVING = true;
private FilesystemPackageCacheManager pcm = null;
@ -454,7 +455,15 @@ public class R3R4ConversionTests implements ITransformerServices, IValidatorReso
}
@Override
public ReferenceValidationPolicy validationPolicy(Object appContext, String path, String url) {
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
return ReferenceValidationPolicy.IGNORE;
}
@Override
public ReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext,
String containerType, String containerId,
Element.SpecialElement containingResourceType, String path,
String url) {
return ReferenceValidationPolicy.IGNORE;
}

View File

@ -4,7 +4,6 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -20,7 +19,6 @@ import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
@ -37,7 +35,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;

View File

@ -5,7 +5,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
@ -16,9 +15,6 @@ import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.convertors.conv10_50.VersionConvertor_10_50;
import org.hl7.fhir.convertors.conv14_50.VersionConvertor_14_50;
import org.hl7.fhir.convertors.conv30_50.VersionConvertor_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
@ -32,7 +28,6 @@ import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.elementmodel.ObjectConverter;
import org.hl7.fhir.r5.elementmodel.SHCParser;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Base;
@ -48,11 +43,13 @@ import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.IResourceValidator.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.r5.utils.IResourceValidator.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
import org.hl7.fhir.utilities.SimpleHTTPClient;
import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult;
import org.hl7.fhir.utilities.TextFile;
@ -80,7 +77,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@RunWith(Parameterized.class)
public class ValidationTests implements IEvaluationContext, IValidatorResourceFetcher {
public class ValidationTests implements IEvaluationContext, IValidatorResourceFetcher, IValidationPolicyAdvisor {
public final static boolean PRINT_OUTPUT_TO_CONSOLE = true;
@ -179,6 +176,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
} else {
val.setFetcher(this);
}
val.setPolicyAdvisor(this);
if (content.has("allowed-extension-domain"))
val.getExtensionDomains().add(content.get("allowed-extension-domain").getAsString());
if (content.has("allowed-extension-domains"))
@ -509,13 +509,24 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
}
@Override
public ReferenceValidationPolicy validationPolicy(IResourceValidator validator, Object appContext, String path, String url) {
if (content.has("validate"))
return ReferenceValidationPolicy.valueOf(content.get("validate").getAsString());
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
if (content.has("validateReference"))
return ReferenceValidationPolicy.valueOf(content.get("validateReference").getAsString());
else
return ReferenceValidationPolicy.IGNORE;
}
@Override
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext,
String containerType, String containerId,
Element.SpecialElement containingResourceType,
String path, String url) {
if (content.has("validateContains"))
return ContainedReferenceValidationPolicy.valueOf(content.get("validateContains").getAsString());
else
return ContainedReferenceValidationPolicy.CHECK_VALID;
}
@Override
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException {
return !url.contains("example.org") && !url.startsWith("http://hl7.org/fhir/invalid");

View File

@ -14,12 +14,12 @@
HAPI FHIR
-->
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.1-SNAPSHOT</version>
<version>5.6.2-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.77</validator_test_case_version>
<validator_test_case_version>1.1.79-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.7.1</junit_jupiter_version>
<junit_platform_launcher_version>1.7.1</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M5</maven_surefire_version>