Merge pull request #1390 from hapifhir/2023-08-gg-flat-draft-bugs-version-rendering

2023 08 gg flat draft bugs version rendering
This commit is contained in:
Grahame Grieve 2023-08-13 09:56:44 +10:00 committed by GitHub
commit d136c0c4f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 825 additions and 266 deletions

View File

@ -93,6 +93,7 @@ public class FHIRToolingClient {
public void initialize(String baseServiceUrl) throws URISyntaxException { public void initialize(String baseServiceUrl) throws URISyntaxException {
base = baseServiceUrl; base = baseServiceUrl;
client.setBase(base);
resourceAddress = new ResourceAddress(baseServiceUrl); resourceAddress = new ResourceAddress(baseServiceUrl);
this.allowedVersions = supportableVersions(); this.allowedVersions = supportableVersions();
this.maxResultSetSize = -1; this.maxResultSetSize = -1;

View File

@ -22,6 +22,16 @@ public class Client {
private ToolingClientLogger logger; private ToolingClientLogger logger;
private int retryCount; private int retryCount;
private long timeout = DEFAULT_TIMEOUT; private long timeout = DEFAULT_TIMEOUT;
private String base;
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public ToolingClientLogger getLogger() { public ToolingClientLogger getLogger() {
return logger; return logger;
@ -167,7 +177,7 @@ public class Client {
String message, String message,
int retryCount, int retryCount,
long timeout) throws IOException { long timeout) throws IOException {
return new FhirRequestBuilder(request) return new FhirRequestBuilder(request, base)
.withLogger(logger) .withLogger(logger)
.withResourceFormat(resourceFormat) .withResourceFormat(resourceFormat)
.withRetryCount(retryCount) .withRetryCount(retryCount)
@ -183,7 +193,7 @@ public class Client {
String message, String message,
int retryCount, int retryCount,
long timeout) throws IOException { long timeout) throws IOException {
return new FhirRequestBuilder(request) return new FhirRequestBuilder(request, base)
.withLogger(logger) .withLogger(logger)
.withResourceFormat(resourceFormat) .withResourceFormat(resourceFormat)
.withRetryCount(retryCount) .withRetryCount(retryCount)

View File

@ -59,9 +59,11 @@ public class FhirRequestBuilder {
* {@link ToolingClientLogger} for log output. * {@link ToolingClientLogger} for log output.
*/ */
private ToolingClientLogger logger = null; private ToolingClientLogger logger = null;
private String source;
public FhirRequestBuilder(Request.Builder httpRequest) { public FhirRequestBuilder(Request.Builder httpRequest, String source) {
this.httpRequest = httpRequest; this.httpRequest = httpRequest;
this.source = source;
} }
/** /**
@ -265,9 +267,9 @@ public class FhirRequestBuilder {
error = (OperationOutcome) resource; error = (OperationOutcome) resource;
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response: " + ioe.getMessage(), ioe); throw new EFhirClientException("Error reading Http Response from "+source+": " + ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message: " + e.getMessage(), e); throw new EFhirClientException("Error parsing response message from "+source+": " + e.getMessage(), e);
} }
} }
@ -301,12 +303,12 @@ public class FhirRequestBuilder {
} }
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response", ioe); throw new EFhirClientException("Error reading Http Response from "+source+": "+ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message", e); throw new EFhirClientException("Error parsing response message from "+source+":"+e.getMessage(), e);
} }
if (error != null) { if (error != null) {
throw new EFhirClientException("Error from server: " + ResourceUtilities.getErrorDescription(error), error); throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} }
return feed; return feed;
} }

View File

@ -47,7 +47,7 @@ public class FhirRequestBuilderTests {
final Request.Builder requestBuilder = new Request.Builder() final Request.Builder requestBuilder = new Request.Builder()
.url(DUMMY_URL); .url(DUMMY_URL);
final FhirRequestBuilder fhirRequestBuilder = Mockito.spy(new FhirRequestBuilder(requestBuilder)); final FhirRequestBuilder fhirRequestBuilder = Mockito.spy(new FhirRequestBuilder(requestBuilder, "http://local/local"));
@Mock @Mock
OkHttpClient client; OkHttpClient client;

View File

@ -93,6 +93,7 @@ public class FHIRToolingClient {
public void initialize(String baseServiceUrl) throws URISyntaxException { public void initialize(String baseServiceUrl) throws URISyntaxException {
base = baseServiceUrl; base = baseServiceUrl;
client.setBase(base);
resourceAddress = new ResourceAddress(baseServiceUrl); resourceAddress = new ResourceAddress(baseServiceUrl);
this.maxResultSetSize = -1; this.maxResultSetSize = -1;
} }

View File

@ -23,6 +23,16 @@ public class Client {
private FhirLoggingInterceptor fhirLoggingInterceptor; private FhirLoggingInterceptor fhirLoggingInterceptor;
private int retryCount; private int retryCount;
private long timeout = DEFAULT_TIMEOUT; private long timeout = DEFAULT_TIMEOUT;
private String base;
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public ToolingClientLogger getLogger() { public ToolingClientLogger getLogger() {
return logger; return logger;
@ -131,7 +141,7 @@ public class Client {
public <T extends Resource> Bundle executeBundleRequest(Request.Builder request, String resourceFormat, public <T extends Resource> Bundle executeBundleRequest(Request.Builder request, String resourceFormat,
Headers headers, String message, int retryCount, long timeout) throws IOException { Headers headers, String message, int retryCount, long timeout) throws IOException {
return new FhirRequestBuilder(request).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat) return new FhirRequestBuilder(request, base).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat)
.withRetryCount(retryCount).withMessage(message) .withRetryCount(retryCount).withMessage(message)
.withHeaders(headers == null ? new Headers.Builder().build() : headers) .withHeaders(headers == null ? new Headers.Builder().build() : headers)
.withTimeout(timeout, TimeUnit.MILLISECONDS).executeAsBatch(); .withTimeout(timeout, TimeUnit.MILLISECONDS).executeAsBatch();
@ -139,7 +149,7 @@ public class Client {
public <T extends Resource> ResourceRequest<T> executeFhirRequest(Request.Builder request, String resourceFormat, public <T extends Resource> ResourceRequest<T> executeFhirRequest(Request.Builder request, String resourceFormat,
Headers headers, String message, int retryCount, long timeout) throws IOException { Headers headers, String message, int retryCount, long timeout) throws IOException {
return new FhirRequestBuilder(request).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat) return new FhirRequestBuilder(request, base).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat)
.withRetryCount(retryCount).withMessage(message) .withRetryCount(retryCount).withMessage(message)
.withHeaders(headers == null ? new Headers.Builder().build() : headers) .withHeaders(headers == null ? new Headers.Builder().build() : headers)
.withTimeout(timeout, TimeUnit.MILLISECONDS).execute(); .withTimeout(timeout, TimeUnit.MILLISECONDS).execute();

View File

@ -58,9 +58,11 @@ public class FhirRequestBuilder {
* {@link FhirLoggingInterceptor} for log output. * {@link FhirLoggingInterceptor} for log output.
*/ */
private FhirLoggingInterceptor logger = null; private FhirLoggingInterceptor logger = null;
private String source;
public FhirRequestBuilder(Request.Builder httpRequest) { public FhirRequestBuilder(Request.Builder httpRequest, String source) {
this.httpRequest = httpRequest; this.httpRequest = httpRequest;
this.source = source;
} }
/** /**
@ -264,9 +266,9 @@ public class FhirRequestBuilder {
error = (OperationOutcome) resource; error = (OperationOutcome) resource;
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response: " + ioe.getMessage(), ioe); throw new EFhirClientException("Error reading Http Response from "+source+": " + ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message: " + e.getMessage(), e); throw new EFhirClientException("Error parsing response message from "+source+": " + e.getMessage(), e);
} }
} }
@ -296,17 +298,17 @@ public class FhirRequestBuilder {
else if (rf instanceof OperationOutcome && hasError((OperationOutcome) rf)) { else if (rf instanceof OperationOutcome && hasError((OperationOutcome) rf)) {
error = (OperationOutcome) rf; error = (OperationOutcome) rf;
} else { } else {
throw new EFhirClientException("Error reading server response: a resource was returned instead"); throw new EFhirClientException("Error reading server response from "+source+": a resource was returned instead");
} }
} }
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response", ioe); throw new EFhirClientException("Error reading Http Response from "+source+":"+ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message", e); throw new EFhirClientException("Error parsing response message from "+source+":"+e.getMessage(), e);
} }
if (error != null) { if (error != null) {
throw new EFhirClientException("Error from server: " + ResourceUtilities.getErrorDescription(error), error); throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} }
return feed; return feed;
} }

View File

@ -110,6 +110,7 @@ public class FHIRToolingClient {
public void initialize(String baseServiceUrl) throws URISyntaxException { public void initialize(String baseServiceUrl) throws URISyntaxException {
base = baseServiceUrl; base = baseServiceUrl;
client.setBase(base);
resourceAddress = new ResourceAddress(baseServiceUrl); resourceAddress = new ResourceAddress(baseServiceUrl);
this.maxResultSetSize = -1; this.maxResultSetSize = -1;
checkCapabilities(); checkCapabilities();

View File

@ -23,6 +23,16 @@ public class Client {
private int retryCount; private int retryCount;
private long timeout = DEFAULT_TIMEOUT; private long timeout = DEFAULT_TIMEOUT;
private byte[] payload; private byte[] payload;
private String base;
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public ToolingClientLogger getLogger() { public ToolingClientLogger getLogger() {
return logger; return logger;
@ -135,7 +145,7 @@ public class Client {
public <T extends Resource> Bundle executeBundleRequest(Request.Builder request, String resourceFormat, public <T extends Resource> Bundle executeBundleRequest(Request.Builder request, String resourceFormat,
Headers headers, String message, int retryCount, long timeout) throws IOException { Headers headers, String message, int retryCount, long timeout) throws IOException {
return new FhirRequestBuilder(request).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat) return new FhirRequestBuilder(request, base).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat)
.withRetryCount(retryCount).withMessage(message) .withRetryCount(retryCount).withMessage(message)
.withHeaders(headers == null ? new Headers.Builder().build() : headers) .withHeaders(headers == null ? new Headers.Builder().build() : headers)
.withTimeout(timeout, TimeUnit.MILLISECONDS).executeAsBatch(); .withTimeout(timeout, TimeUnit.MILLISECONDS).executeAsBatch();
@ -143,7 +153,7 @@ public class Client {
public <T extends Resource> ResourceRequest<T> executeFhirRequest(Request.Builder request, String resourceFormat, public <T extends Resource> ResourceRequest<T> executeFhirRequest(Request.Builder request, String resourceFormat,
Headers headers, String message, int retryCount, long timeout) throws IOException { Headers headers, String message, int retryCount, long timeout) throws IOException {
return new FhirRequestBuilder(request).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat) return new FhirRequestBuilder(request, base).withLogger(fhirLoggingInterceptor).withResourceFormat(resourceFormat)
.withRetryCount(retryCount).withMessage(message) .withRetryCount(retryCount).withMessage(message)
.withHeaders(headers == null ? new Headers.Builder().build() : headers) .withHeaders(headers == null ? new Headers.Builder().build() : headers)
.withTimeout(timeout, TimeUnit.MILLISECONDS).execute(); .withTimeout(timeout, TimeUnit.MILLISECONDS).execute();

View File

@ -52,9 +52,11 @@ public class FhirRequestBuilder {
* {@link FhirLoggingInterceptor} for log output. * {@link FhirLoggingInterceptor} for log output.
*/ */
private FhirLoggingInterceptor logger = null; private FhirLoggingInterceptor logger = null;
private String source;
public FhirRequestBuilder(Request.Builder httpRequest) { public FhirRequestBuilder(Request.Builder httpRequest, String source) {
this.httpRequest = httpRequest; this.httpRequest = httpRequest;
this.source = source;
} }
/** /**
@ -253,9 +255,9 @@ public class FhirRequestBuilder {
error = (OperationOutcome) resource; error = (OperationOutcome) resource;
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response: " + ioe.getMessage(), ioe); throw new EFhirClientException("Error reading Http Response from "+source+": " + ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message: " + e.getMessage(), e); throw new EFhirClientException("Error parsing response message from "+source+": " + e.getMessage(), e);
} }
} }
@ -290,12 +292,12 @@ public class FhirRequestBuilder {
} }
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response", ioe); throw new EFhirClientException("Error reading Http Response from "+source+": "+ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message", e); throw new EFhirClientException("Error parsing response message from "+source+": "+e.getMessage(), e);
} }
if (error != null) { if (error != null) {
throw new EFhirClientException("Error from server: " + ResourceUtilities.getErrorDescription(error), error); throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} }
return feed; return feed;
} }

View File

@ -9,6 +9,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.ChangeAnalysisState;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts; import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType; import org.hl7.fhir.r5.model.CanonicalType;
@ -31,11 +32,26 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public abstract class CanonicalResourceComparer extends ResourceComparer { public abstract class CanonicalResourceComparer extends ResourceComparer {
public enum ChangeAnalysisState {
Unknown, NotChanged, Changed, CannotEvaluate;
boolean noteable() {
return this == Changed || this == CannotEvaluate;
}
}
public abstract class CanonicalResourceComparison<T extends CanonicalResource> extends ResourceComparison { public abstract class CanonicalResourceComparison<T extends CanonicalResource> extends ResourceComparison {
protected T left; protected T left;
protected T right; protected T right;
protected T union; protected T union;
protected T intersection; protected T intersection;
private ChangeAnalysisState changedMetadata = ChangeAnalysisState.Unknown;
private ChangeAnalysisState changedDefinitions = ChangeAnalysisState.Unknown;
private ChangeAnalysisState changedContent = ChangeAnalysisState.Unknown;
private ChangeAnalysisState changedContentInterpretation = ChangeAnalysisState.Unknown;
protected Map<String, StructuralMatch<String>> metadata = new HashMap<>(); protected Map<String, StructuralMatch<String>> metadata = new HashMap<>();
public CanonicalResourceComparison(T left, T right) { public CanonicalResourceComparison(T left, T right) {
@ -80,6 +96,59 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
this.intersection = intersection; this.intersection = intersection;
} }
private ChangeAnalysisState updateState(ChangeAnalysisState newState, ChangeAnalysisState oldState) {
switch (newState) {
case CannotEvaluate:
return ChangeAnalysisState.CannotEvaluate;
case Changed:
if (oldState != ChangeAnalysisState.CannotEvaluate) {
return ChangeAnalysisState.Changed;
}
break;
case NotChanged:
if (oldState == ChangeAnalysisState.Unknown) {
return ChangeAnalysisState.NotChanged;
}
break;
case Unknown:
default:
break;
}
return oldState;
}
public void updatedMetadataState(ChangeAnalysisState state) {
changedMetadata = updateState(state, changedMetadata);
}
public void updateDefinitionsState(ChangeAnalysisState state) {
changedDefinitions = updateState(state, changedDefinitions);
}
public void updateContentState(ChangeAnalysisState state) {
changedContent = updateState(state, changedContent);
}
public void updateContentInterpretationState(ChangeAnalysisState state) {
changedContentInterpretation = updateState(state, changedContentInterpretation);
}
public void updatedMetadataState(boolean state) {
changedMetadata = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedMetadata);
}
public void updateDefinitionsState(boolean state) {
changedDefinitions = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedDefinitions);
}
public void updateContentState(boolean state) {
changedContent = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContent);
}
public void updateContentInterpretationState(boolean state) {
changedContentInterpretation = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContentInterpretation);
}
@Override @Override
protected String toTable() { protected String toTable() {
String s = ""; String s = "";
@ -96,34 +165,75 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
sm.countMessages(cnts); sm.countMessages(cnts);
} }
} }
protected String changeSummary() {
if (!(changedMetadata.noteable() || changedDefinitions.noteable() || changedContent.noteable() || changedContentInterpretation.noteable())) {
return null;
};
CommaSeparatedStringBuilder bc = new CommaSeparatedStringBuilder();
if (changedMetadata == ChangeAnalysisState.CannotEvaluate) {
bc.append("Metadata");
}
if (changedDefinitions == ChangeAnalysisState.CannotEvaluate) {
bc.append("Definitions");
}
if (changedContent == ChangeAnalysisState.CannotEvaluate) {
bc.append("Content");
}
if (changedContentInterpretation == ChangeAnalysisState.CannotEvaluate) {
bc.append("Interpretation");
}
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
if (changedMetadata == ChangeAnalysisState.Changed) {
b.append("Metadata");
}
if (changedDefinitions == ChangeAnalysisState.Changed) {
b.append("Definitions");
}
if (changedContent == ChangeAnalysisState.Changed) {
b.append("Content");
}
if (changedContentInterpretation == ChangeAnalysisState.Changed) {
b.append("Interpretation");
}
return (bc.length() == 0 ? "" : "Error Checking: "+bc.toString()+"; ")+ "Changed: "+b.toString();
}
} }
public CanonicalResourceComparer(ComparisonSession session) { public CanonicalResourceComparer(ComparisonSession session) {
super(session); super(session);
} }
protected void compareMetadata(CanonicalResource left, CanonicalResource right, Map<String, StructuralMatch<String>> comp, CanonicalResourceComparison<? extends CanonicalResource> res) { protected boolean compareMetadata(CanonicalResource left, CanonicalResource right, Map<String, StructuralMatch<String>> comp, CanonicalResourceComparison<? extends CanonicalResource> res) {
comparePrimitives("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res); var changed = false;
comparePrimitives("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res); changed = comparePrimitives("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res) || changed;
comparePrimitives("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res); if (session.getForVersion() == null) {
comparePrimitives("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res); changed = comparePrimitives("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res) || changed;
comparePrimitives("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res); }
comparePrimitives("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res); changed = comparePrimitives("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res) || changed;
comparePrimitives("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res); changed = comparePrimitives("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res) || changed;
comparePrimitives("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res); changed = comparePrimitives("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res) || changed;
comparePrimitives("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res); changed = comparePrimitives("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res) || changed;
comparePrimitives("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res); if (session.getForVersion() == null) {
comparePrimitives("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res); changed = comparePrimitives("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res) || changed;
compareCodeableConceptList("jurisdiction", left.getJurisdiction(), right.getJurisdiction(), comp, IssueSeverity.INFORMATION, res, res.getUnion().getJurisdiction(), res.getIntersection().getJurisdiction()); }
changed = comparePrimitives("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res) || changed;
changed = comparePrimitives("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res) || changed;
changed = comparePrimitives("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res) || changed;
changed = comparePrimitives("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res) || changed;
changed = compareCodeableConceptList("jurisdiction", left.getJurisdiction(), right.getJurisdiction(), comp, IssueSeverity.INFORMATION, res, res.getUnion().getJurisdiction(), res.getIntersection().getJurisdiction()) || changed;
return changed;
} }
protected void compareCodeableConceptList(String name, List<CodeableConcept> left, List<CodeableConcept> right, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res, List<CodeableConcept> union, List<CodeableConcept> intersection ) { protected boolean compareCodeableConceptList(String name, List<CodeableConcept> left, List<CodeableConcept> right, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res, List<CodeableConcept> union, List<CodeableConcept> intersection ) {
boolean result = false;
List<CodeableConcept> matchR = new ArrayList<>(); List<CodeableConcept> matchR = new ArrayList<>();
StructuralMatch<String> combined = new StructuralMatch<String>(); StructuralMatch<String> combined = new StructuralMatch<String>();
for (CodeableConcept l : left) { for (CodeableConcept l : left) {
CodeableConcept r = findCodeableConceptInList(right, l); CodeableConcept r = findCodeableConceptInList(right, l);
if (r == null) { if (r == null) {
union.add(l); union.add(l);
result = true;
combined.getChildren().add(new StructuralMatch<String>(gen(l), vm(IssueSeverity.INFORMATION, "Removed the item '"+gen(l)+"'", fhirType()+"."+name, res.getMessages()))); combined.getChildren().add(new StructuralMatch<String>(gen(l), vm(IssueSeverity.INFORMATION, "Removed the item '"+gen(l)+"'", fhirType()+"."+name, res.getMessages())));
} else { } else {
matchR.add(r); matchR.add(r);
@ -131,15 +241,20 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
intersection.add(r); intersection.add(r);
StructuralMatch<String> sm = new StructuralMatch<String>(gen(l), gen(r)); StructuralMatch<String> sm = new StructuralMatch<String>(gen(l), gen(r));
combined.getChildren().add(sm); combined.getChildren().add(sm);
if (sm.isDifferent()) {
result = true;
}
} }
} }
for (CodeableConcept r : right) { for (CodeableConcept r : right) {
if (!matchR.contains(r)) { if (!matchR.contains(r)) {
union.add(r); union.add(r);
result = true;
combined.getChildren().add(new StructuralMatch<String>(vm(IssueSeverity.INFORMATION, "Added the item '"+gen(r)+"'", fhirType()+"."+name, res.getMessages()), gen(r))); combined.getChildren().add(new StructuralMatch<String>(vm(IssueSeverity.INFORMATION, "Added the item '"+gen(r)+"'", fhirType()+"."+name, res.getMessages()), gen(r)));
} }
} }
comp.put(name, combined); comp.put(name, combined);
return result;
} }
@ -233,7 +348,7 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
protected void comparePrimitives(String name, PrimitiveType l, PrimitiveType r, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res) { protected boolean comparePrimitives(String name, PrimitiveType l, PrimitiveType r, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res) {
StructuralMatch<String> match = null; StructuralMatch<String> match = null;
if (l.isEmpty() && r.isEmpty()) { if (l.isEmpty() && r.isEmpty()) {
match = new StructuralMatch<>(null, null, null); match = new StructuralMatch<>(null, null, null);
@ -256,6 +371,7 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
} }
} }
comp.put(name, match); comp.put(name, match);
return match.isDifferent();
} }
protected abstract String fhirType(); protected abstract String fhirType();

View File

@ -33,7 +33,6 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
private StructuralMatch<ConceptDefinitionComponent> combined; private StructuralMatch<ConceptDefinitionComponent> combined;
private Map<String, String> propMap = new HashMap<>(); // right to left; left retains it's name private Map<String, String> propMap = new HashMap<>(); // right to left; left retains it's name
public CodeSystemComparison(CodeSystem left, CodeSystem right) { public CodeSystemComparison(CodeSystem left, CodeSystem right) {
super(left, right); super(left, right);
combined = new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(); // base combined = new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(); // base
@ -54,8 +53,14 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
@Override @Override
protected String summary() { protected String summary() {
return "CodeSystem: "+left.present()+" vs "+right.present(); String res = "CodeSystem: "+left.present()+" vs "+right.present();
String ch = changeSummary();
if (ch != null) {
res = res + ". "+ch;
} }
return res;
}
@Override @Override
protected String fhirType() { protected String fhirType() {
@ -114,14 +119,18 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
cs1.setDate(new Date()); cs1.setDate(new Date());
cs1.getProperty().addAll(cs.getProperty()); cs1.getProperty().addAll(cs.getProperty());
compareMetadata(left, right, res.getMetadata(), res); boolean ch = compareMetadata(left, right, res.getMetadata(), res);
comparePrimitives("caseSensitive", left.getCaseSensitiveElement(), right.getCaseSensitiveElement(), res.getMetadata(), IssueSeverity.ERROR, res); ch = comparePrimitives("versionNeeded", left.getVersionNeededElement(), right.getVersionNeededElement(), res.getMetadata(), IssueSeverity.INFORMATION, res) || ch;
comparePrimitives("hierarchyMeaning", left.getHierarchyMeaningElement(), right.getHierarchyMeaningElement(), res.getMetadata(), IssueSeverity.ERROR, res); ch = comparePrimitives("compositional", left.getCompositionalElement(), right.getCompositionalElement(), res.getMetadata(), IssueSeverity.WARNING, res) || ch;
comparePrimitives("compositional", left.getCompositionalElement(), right.getCompositionalElement(), res.getMetadata(), IssueSeverity.WARNING, res); res.updatedMetadataState(ch);
comparePrimitives("versionNeeded", left.getVersionNeededElement(), right.getVersionNeededElement(), res.getMetadata(), IssueSeverity.INFORMATION, res); ch = false;
comparePrimitives("content", left.getContentElement(), right.getContentElement(), res.getMetadata(), IssueSeverity.WARNING, res); ch = comparePrimitives("caseSensitive", left.getCaseSensitiveElement(), right.getCaseSensitiveElement(), res.getMetadata(), IssueSeverity.ERROR, res) || ch;
ch = comparePrimitives("hierarchyMeaning", left.getHierarchyMeaningElement(), right.getHierarchyMeaningElement(), res.getMetadata(), IssueSeverity.ERROR, res) || ch;
ch = comparePrimitives("content", left.getContentElement(), right.getContentElement(), res.getMetadata(), IssueSeverity.WARNING, res);
ch = compareConcepts(left.getConcept(), right.getConcept(), res.getCombined(), res.getUnion().getConcept(), res.getIntersection().getConcept(), res.getUnion(), res.getIntersection(), res, "CodeSystem.concept") || ch;
res.updateDefinitionsState(ch);
compareConcepts(left.getConcept(), right.getConcept(), res.getCombined(), res.getUnion().getConcept(), res.getIntersection().getConcept(), res.getUnion(), res.getIntersection(), res, "CodeSystem.concept");
return res; return res;
} }
@ -153,13 +162,15 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
} }
private void compareConcepts(List<ConceptDefinitionComponent> left, List<ConceptDefinitionComponent> right, StructuralMatch<ConceptDefinitionComponent> combined, private boolean compareConcepts(List<ConceptDefinitionComponent> left, List<ConceptDefinitionComponent> right, StructuralMatch<ConceptDefinitionComponent> combined,
List<ConceptDefinitionComponent> union, List<ConceptDefinitionComponent> intersection, CodeSystem csU, CodeSystem csI, CodeSystemComparison res, String path) { List<ConceptDefinitionComponent> union, List<ConceptDefinitionComponent> intersection, CodeSystem csU, CodeSystem csI, CodeSystemComparison res, String path) {
boolean result = false;
List<ConceptDefinitionComponent> matchR = new ArrayList<>(); List<ConceptDefinitionComponent> matchR = new ArrayList<>();
for (ConceptDefinitionComponent l : left) { for (ConceptDefinitionComponent l : left) {
ConceptDefinitionComponent r = findInList(right, l); ConceptDefinitionComponent r = findInList(right, l);
if (r == null) { if (r == null) {
union.add(l); union.add(l);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, vmI(IssueSeverity.INFORMATION, "Removed this concept", path))); combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, vmI(IssueSeverity.INFORMATION, "Removed this concept", path)));
} else { } else {
matchR.add(r); matchR.add(r);
@ -168,17 +179,23 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
union.add(cdM); union.add(cdM);
intersection.add(cdI); intersection.add(cdI);
StructuralMatch<ConceptDefinitionComponent> sm = new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, r); StructuralMatch<ConceptDefinitionComponent> sm = new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, r);
compare(sm.getMessages(), l, r, path+".where(code='"+l.getCode()+"')", res); if (compare(sm.getMessages(), l, r, path+".where(code='"+l.getCode()+"')", res)) {
result = true;
}
combined.getChildren().add(sm); combined.getChildren().add(sm);
compareConcepts(l.getConcept(), r.getConcept(), sm, cdM.getConcept(), cdI.getConcept(), csU, csI, res, path+".where(code='"+l.getCode()+"').concept"); if (compareConcepts(l.getConcept(), r.getConcept(), sm, cdM.getConcept(), cdI.getConcept(), csU, csI, res, path+".where(code='"+l.getCode()+"').concept")) {
result = true;
}
} }
} }
for (ConceptDefinitionComponent r : right) { for (ConceptDefinitionComponent r : right) {
if (!matchR.contains(r)) { if (!matchR.contains(r)) {
union.add(r); union.add(r);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r)); combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
} }
} }
return result;
} }
private ConceptDefinitionComponent findInList(List<ConceptDefinitionComponent> list, ConceptDefinitionComponent item) { private ConceptDefinitionComponent findInList(List<ConceptDefinitionComponent> list, ConceptDefinitionComponent item) {
@ -190,24 +207,30 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
return null; return null;
} }
private void compare(List<ValidationMessage> msgs, ConceptDefinitionComponent l, ConceptDefinitionComponent r, String path, CodeSystemComparison res) { private boolean compare(List<ValidationMessage> msgs, ConceptDefinitionComponent l, ConceptDefinitionComponent r, String path, CodeSystemComparison res) {
compareStrings(path, msgs, l.getDisplay(), r.getDisplay(), "display", IssueSeverity.WARNING, res); boolean result = false;
compareStrings(path, msgs, l.getDefinition(), r.getDefinition(), "definition", IssueSeverity.INFORMATION, res); result = compareStrings(path, msgs, l.getDisplay(), r.getDisplay(), "display", IssueSeverity.WARNING, res) || result;
result = compareStrings(path, msgs, l.getDefinition(), r.getDefinition(), "definition", IssueSeverity.INFORMATION, res) || result;
return result;
} }
private void compareStrings(String path, List<ValidationMessage> msgs, String left, String right, String name, IssueSeverity level, CodeSystemComparison res) { private boolean compareStrings(String path, List<ValidationMessage> msgs, String left, String right, String name, IssueSeverity level, CodeSystemComparison res) {
if (!Utilities.noString(right)) { if (!Utilities.noString(right)) {
if (Utilities.noString(left)) { if (Utilities.noString(left)) {
msgs.add(vmI(level, "Value for "+name+" added", path)); msgs.add(vmI(level, "Value for "+name+" added", path));
return true;
} else if (!left.equals(right)) { } else if (!left.equals(right)) {
if (level != IssueSeverity.NULL) { if (level != IssueSeverity.NULL) {
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path+"."+name, "Changed value for "+name+": '"+left+"' vs '"+right+"'", level)); res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path+"."+name, "Changed value for "+name+": '"+left+"' vs '"+right+"'", level));
} }
msgs.add(vmI(level, name+" changed from left to right", path)); msgs.add(vmI(level, name+" changed from left to right", path));
return true;
} }
} else if (!Utilities.noString(left)) { } else if (!Utilities.noString(left)) {
msgs.add(vmI(level, "Value for "+name+" removed", path)); msgs.add(vmI(level, "Value for "+name+" removed", path));
return true;
} }
return false;
} }
private ConceptDefinitionComponent merge(ConceptDefinitionComponent l, ConceptDefinitionComponent r, List<PropertyComponent> destProps, CodeSystemComparison res) { private ConceptDefinitionComponent merge(ConceptDefinitionComponent l, ConceptDefinitionComponent r, List<PropertyComponent> destProps, CodeSystemComparison res) {

View File

@ -175,6 +175,7 @@ public class ComparisonRenderer implements IEvaluationContext {
vars.put("rightId", new StringType(comp.getRight().getId())); vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl())); vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl())); vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("summary", new StringType(comp.summary()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp)))); vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", "")))); vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("concepts", new StringType(new XhtmlComposer(true).compose(cs.renderConcepts(comp, "", "")))); vars.put("concepts", new StringType(new XhtmlComposer(true).compose(cs.renderConcepts(comp, "", ""))));
@ -198,6 +199,7 @@ public class ComparisonRenderer implements IEvaluationContext {
vars.put("rightId", new StringType(comp.getRight().getId())); vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl())); vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl())); vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("summary", new StringType(comp.summary()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp)))); vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", "")))); vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("compose", new StringType(new XhtmlComposer(true).compose(cs.renderCompose(comp, "", "")))); vars.put("compose", new StringType(new XhtmlComposer(true).compose(cs.renderCompose(comp, "", ""))));

View File

@ -32,6 +32,8 @@ public class ComparisonSession {
private String sessiondId; private String sessiondId;
private int count; private int count;
private boolean debug; private boolean debug;
private String forVersion;
private boolean annotate;
private String title; private String title;
private ProfileKnowledgeProvider pkpLeft; private ProfileKnowledgeProvider pkpLeft;
private ProfileKnowledgeProvider pkpRight; private ProfileKnowledgeProvider pkpRight;
@ -164,4 +166,22 @@ public class ComparisonSession {
public ProfileKnowledgeProvider getPkpRight() { public ProfileKnowledgeProvider getPkpRight() {
return pkpRight; return pkpRight;
} }
public String getForVersion() {
return forVersion;
}
public void setForVersion(String forVersion) {
this.forVersion = forVersion;
}
public boolean isAnnotate() {
return annotate;
}
public void setAnnotate(boolean annotate) {
this.annotate = annotate;
}
} }

View File

@ -114,6 +114,8 @@ public class StructuralMatch<T> {
return this; return this;
} }
public boolean isDifferent() {
return (left == null) != (right == null) || !messages.isEmpty();
}
} }

View File

@ -8,6 +8,7 @@ import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts; import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation.AnotationType;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalType; import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.Element; import org.hl7.fhir.r5.model.Element;
@ -67,7 +68,12 @@ public class ValueSetComparer extends CanonicalResourceComparer {
@Override @Override
protected String summary() { protected String summary() {
return "ValueSet: "+left.present()+" vs "+right.present(); String res = "ValueSet: "+left.present()+" vs "+right.present();
String ch = changeSummary();
if (ch != null) {
res = res + ". "+ch;
}
return res;
} }
@Override @Override
@ -118,28 +124,34 @@ public class ValueSetComparer extends CanonicalResourceComparer {
vs1.setStatus(left.getStatus()); vs1.setStatus(left.getStatus());
vs1.setDate(new Date()); vs1.setDate(new Date());
compareMetadata(left, right, res.getMetadata(), res); var ch = compareMetadata(left, right, res.getMetadata(), res);
comparePrimitives("immutable", left.getImmutableElement(), right.getImmutableElement(), res.getMetadata(), IssueSeverity.WARNING, res); var def = false;
ch = comparePrimitives("immutable", left.getImmutableElement(), right.getImmutableElement(), res.getMetadata(), IssueSeverity.WARNING, res) || ch;
if (left.hasCompose() || right.hasCompose()) { if (left.hasCompose() || right.hasCompose()) {
comparePrimitives("compose.lockedDate", left.getCompose().getLockedDateElement(), right.getCompose().getLockedDateElement(), res.getMetadata(), IssueSeverity.WARNING, res); ch = comparePrimitives("compose.lockedDate", left.getCompose().getLockedDateElement(), right.getCompose().getLockedDateElement(), res.getMetadata(), IssueSeverity.WARNING, res) || ch;
comparePrimitives("compose.inactive", left.getCompose().getInactiveElement(), right.getCompose().getInactiveElement(), res.getMetadata(), IssueSeverity.WARNING, res); def = comparePrimitives("compose.inactive", left.getCompose().getInactiveElement(), right.getCompose().getInactiveElement(), res.getMetadata(), IssueSeverity.WARNING, res) || def;
} }
res.updatedMetadataState(ch);
compareCompose(left.getCompose(), right.getCompose(), res, res.getUnion().getCompose(), res.getIntersection().getCompose()); def = compareCompose(left.getCompose(), right.getCompose(), res, res.getUnion().getCompose(), res.getIntersection().getCompose()) || def;
res.updateDefinitionsState(def);
compareExpansions(left, right, res); compareExpansions(left, right, res);
return res; return res;
} }
private boolean compareCompose(ValueSetComposeComponent left, ValueSetComposeComponent right, ValueSetComparison res, ValueSetComposeComponent union, ValueSetComposeComponent intersection) {
boolean def = false;
private void compareCompose(ValueSetComposeComponent left, ValueSetComposeComponent right, ValueSetComparison res, ValueSetComposeComponent union, ValueSetComposeComponent intersection) {
// first, the includes // first, the includes
List<ConceptSetComponent> matchR = new ArrayList<>(); List<ConceptSetComponent> matchR = new ArrayList<>();
for (ConceptSetComponent l : left.getInclude()) { for (ConceptSetComponent l : left.getInclude()) {
ConceptSetComponent r = findInList(right.getInclude(), l, left.getInclude()); ConceptSetComponent r = findInList(right.getInclude(), l, left.getInclude());
if (r == null) { if (r == null) {
union.getInclude().add(l); union.getInclude().add(l);
res.updateContentState(true);
res.getIncludes().getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed Include", "ValueSet.compose.include"))); res.getIncludes().getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed Include", "ValueSet.compose.include")));
if (session.isAnnotate()) {
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "include", l);
}
} else { } else {
matchR.add(r); matchR.add(r);
ConceptSetComponent csM = new ConceptSetComponent(); ConceptSetComponent csM = new ConceptSetComponent();
@ -148,13 +160,17 @@ public class ValueSetComparer extends CanonicalResourceComparer {
intersection.getInclude().add(csI); intersection.getInclude().add(csI);
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r);
res.getIncludes().getChildren().add(sm); res.getIncludes().getChildren().add(sm);
compareDefinitions(l, r, sm, csM, csI); def = compareDefinitions(l, r, sm, csM, csI, res) || def;
} }
} }
for (ConceptSetComponent r : right.getInclude()) { for (ConceptSetComponent r : right.getInclude()) {
if (!matchR.contains(r)) { if (!matchR.contains(r)) {
union.getInclude().add(r); union.getInclude().add(r);
res.updateContentState(true);
res.getIncludes().getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added Include", "ValueSet.compose.include"), r)); res.getIncludes().getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added Include", "ValueSet.compose.include"), r));
if (session.isAnnotate()) {
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
}
} }
} }
@ -164,6 +180,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
ConceptSetComponent r = findInList(right.getExclude(), l, left.getExclude()); ConceptSetComponent r = findInList(right.getExclude(), l, left.getExclude());
if (r == null) { if (r == null) {
union.getExclude().add(l); union.getExclude().add(l);
res.updateContentState(true);
res.getExcludes().getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed Exclude", "ValueSet.compose.exclude"))); res.getExcludes().getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed Exclude", "ValueSet.compose.exclude")));
} else { } else {
matchR.add(r); matchR.add(r);
@ -173,15 +190,17 @@ public class ValueSetComparer extends CanonicalResourceComparer {
intersection.getExclude().add(csI); intersection.getExclude().add(csI);
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r);
res.getExcludes().getChildren().add(sm); res.getExcludes().getChildren().add(sm);
compareDefinitions(l, r, sm, csM, csI); def = compareDefinitions(l, r, sm, csM, csI, res) || def;
} }
} }
for (ConceptSetComponent r : right.getExclude()) { for (ConceptSetComponent r : right.getExclude()) {
if (!matchR.contains(r)) { if (!matchR.contains(r)) {
union.getExclude().add(r); union.getExclude().add(r);
res.updateContentState(true);
res.getExcludes().getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added Exclude", "ValueSet.compose.exclude"), r)); res.getExcludes().getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added Exclude", "ValueSet.compose.exclude"), r));
} }
} }
return def;
} }
private ConceptSetComponent findInList(List<ConceptSetComponent> matches, ConceptSetComponent item, List<ConceptSetComponent> source) { private ConceptSetComponent findInList(List<ConceptSetComponent> matches, ConceptSetComponent item, List<ConceptSetComponent> source) {
@ -218,13 +237,15 @@ public class ValueSetComparer extends CanonicalResourceComparer {
} }
private void compareDefinitions(ConceptSetComponent left, ConceptSetComponent right, StructuralMatch<Element> combined, ConceptSetComponent union, ConceptSetComponent intersection) { private boolean compareDefinitions(ConceptSetComponent left, ConceptSetComponent right, StructuralMatch<Element> combined, ConceptSetComponent union, ConceptSetComponent intersection, ValueSetComparison res) {
boolean def = false;
// system must match, but the rest might not. we're going to do the full comparison whatever, so the outcome looks consistent to the user // system must match, but the rest might not. we're going to do the full comparison whatever, so the outcome looks consistent to the user
List<CanonicalType> matchVSR = new ArrayList<>(); List<CanonicalType> matchVSR = new ArrayList<>();
for (CanonicalType l : left.getValueSet()) { for (CanonicalType l : left.getValueSet()) {
CanonicalType r = findInList(right.getValueSet(), l, left.getValueSet()); CanonicalType r = findInList(right.getValueSet(), l, left.getValueSet());
if (r == null) { if (r == null) {
union.getValueSet().add(l); union.getValueSet().add(l);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed ValueSet", "ValueSet.compose.include.valueSet"))); combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed ValueSet", "ValueSet.compose.include.valueSet")));
} else { } else {
matchVSR.add(r); matchVSR.add(r);
@ -234,8 +255,10 @@ public class ValueSetComparer extends CanonicalResourceComparer {
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, null); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, null);
combined.getChildren().add(sm); combined.getChildren().add(sm);
} else { } else {
// it's not possible to get here?
union.getValueSet().add(l); union.getValueSet().add(l);
union.getValueSet().add(r); union.getValueSet().add(r);
res.updateContentState(true);
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Values are different", "ValueSet.compose.include.valueSet")); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Values are different", "ValueSet.compose.include.valueSet"));
combined.getChildren().add(sm); combined.getChildren().add(sm);
} }
@ -244,6 +267,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
for (CanonicalType r : right.getValueSet()) { for (CanonicalType r : right.getValueSet()) {
if (!matchVSR.contains(r)) { if (!matchVSR.contains(r)) {
union.getValueSet().add(r); union.getValueSet().add(r);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Add ValueSet", "ValueSet.compose.include.valueSet"), r)); combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Add ValueSet", "ValueSet.compose.include.valueSet"), r));
} }
} }
@ -253,6 +277,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
ConceptReferenceComponent r = findInList(right.getConcept(), l, left.getConcept()); ConceptReferenceComponent r = findInList(right.getConcept(), l, left.getConcept());
if (r == null) { if (r == null) {
union.getConcept().add(l); union.getConcept().add(l);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this Concept", "ValueSet.compose.include.concept"))); combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this Concept", "ValueSet.compose.include.concept")));
} else { } else {
matchCR.add(r); matchCR.add(r);
@ -263,12 +288,14 @@ public class ValueSetComparer extends CanonicalResourceComparer {
intersection.getConcept().add(ci); intersection.getConcept().add(ci);
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r);
combined.getChildren().add(sm); combined.getChildren().add(sm);
compareConcepts(l, r, sm, cu, ci); def = compareConcepts(l, r, sm, cu, ci) || def;
} else { } else {
// not that it's possible to get here?
union.getConcept().add(l); union.getConcept().add(l);
union.getConcept().add(r); union.getConcept().add(r);
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Concepts are different", "ValueSet.compose.include.concept")); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Concepts are different", "ValueSet.compose.include.concept"));
combined.getChildren().add(sm); combined.getChildren().add(sm);
res.updateContentState(true);
compareConcepts(l, r, sm, null, null); compareConcepts(l, r, sm, null, null);
} }
} }
@ -276,6 +303,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
for (ConceptReferenceComponent r : right.getConcept()) { for (ConceptReferenceComponent r : right.getConcept()) {
if (!matchCR.contains(r)) { if (!matchCR.contains(r)) {
union.getConcept().add(r); union.getConcept().add(r);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this Concept", "ValueSet.compose.include.concept"), r)); combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this Concept", "ValueSet.compose.include.concept"), r));
} }
} }
@ -285,6 +313,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
ConceptSetFilterComponent r = findInList(right.getFilter(), l, left.getFilter()); ConceptSetFilterComponent r = findInList(right.getFilter(), l, left.getFilter());
if (r == null) { if (r == null) {
union.getFilter().add(l); union.getFilter().add(l);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this item", "ValueSet.compose.include.filter"))); combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this item", "ValueSet.compose.include.filter")));
} else { } else {
matchFR.add(r); matchFR.add(r);
@ -295,11 +324,14 @@ public class ValueSetComparer extends CanonicalResourceComparer {
intersection.getFilter().add(ci); intersection.getFilter().add(ci);
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r);
combined.getChildren().add(sm); combined.getChildren().add(sm);
compareFilters(l, r, sm, cu, ci); if (!compareFilters(l, r, sm, cu, ci)) {
res.updateContentState(true);
}
} else { } else {
union.getFilter().add(l); union.getFilter().add(l);
union.getFilter().add(r); union.getFilter().add(r);
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Codes are different", "ValueSet.compose.include.filter")); StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Codes are different", "ValueSet.compose.include.filter"));
res.updateContentState(true);
combined.getChildren().add(sm); combined.getChildren().add(sm);
compareFilters(l, r, sm, null, null); compareFilters(l, r, sm, null, null);
} }
@ -308,12 +340,15 @@ public class ValueSetComparer extends CanonicalResourceComparer {
for (ConceptSetFilterComponent r : right.getFilter()) { for (ConceptSetFilterComponent r : right.getFilter()) {
if (!matchFR.contains(r)) { if (!matchFR.contains(r)) {
union.getFilter().add(r); union.getFilter().add(r);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this item", "ValueSet.compose.include.filter"), r)); combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this item", "ValueSet.compose.include.filter"), r));
} }
} }
return def;
} }
private void compareConcepts(ConceptReferenceComponent l, ConceptReferenceComponent r, StructuralMatch<Element> sm, ConceptReferenceComponent cu, ConceptReferenceComponent ci) { private boolean compareConcepts(ConceptReferenceComponent l, ConceptReferenceComponent r, StructuralMatch<Element> sm, ConceptReferenceComponent cu, ConceptReferenceComponent ci) {
boolean def = false;
sm.getChildren().add(new StructuralMatch<Element>(l.getCodeElement(), r.getCodeElement(), l.getCode().equals(r.getCode()) ? null : vmI(IssueSeverity.INFORMATION, "Codes do not match", "ValueSet.compose.include.concept"))); sm.getChildren().add(new StructuralMatch<Element>(l.getCodeElement(), r.getCodeElement(), l.getCode().equals(r.getCode()) ? null : vmI(IssueSeverity.INFORMATION, "Codes do not match", "ValueSet.compose.include.concept")));
if (ci != null) { if (ci != null) {
ci.setCode(l.getCode()); ci.setCode(l.getCode());
@ -325,24 +360,28 @@ public class ValueSetComparer extends CanonicalResourceComparer {
ci.setDisplay(r.getDisplay()); ci.setDisplay(r.getDisplay());
cu.setDisplay(r.getDisplay()); cu.setDisplay(r.getDisplay());
} }
def = !l.getDisplay().equals(r.getDisplay());
} else if (l.hasDisplay()) { } else if (l.hasDisplay()) {
sm.getChildren().add(new StructuralMatch<Element>(l.getDisplayElement(), null, vmI(IssueSeverity.INFORMATION, "Display Removed", "ValueSet.compose.include.concept"))); sm.getChildren().add(new StructuralMatch<Element>(l.getDisplayElement(), null, vmI(IssueSeverity.INFORMATION, "Display Removed", "ValueSet.compose.include.concept")));
if (ci != null) { if (ci != null) {
ci.setDisplay(l.getDisplay()); ci.setDisplay(l.getDisplay());
cu.setDisplay(l.getDisplay()); cu.setDisplay(l.getDisplay());
} }
def = true;
} else if (r.hasDisplay()) { } else if (r.hasDisplay()) {
sm.getChildren().add(new StructuralMatch<Element>(null, r.getDisplayElement(), vmI(IssueSeverity.INFORMATION, "Display added", "ValueSet.compose.include.concept"))); sm.getChildren().add(new StructuralMatch<Element>(null, r.getDisplayElement(), vmI(IssueSeverity.INFORMATION, "Display added", "ValueSet.compose.include.concept")));
if (ci != null) { if (ci != null) {
ci.setDisplay(r.getDisplay()); ci.setDisplay(r.getDisplay());
cu.setDisplay(r.getDisplay()); cu.setDisplay(r.getDisplay());
} }
def = true;
} else { } else {
sm.getChildren().add(new StructuralMatch<Element>(null, null, vmI(IssueSeverity.INFORMATION, "No Display", "ValueSet.compose.include.concept"))); sm.getChildren().add(new StructuralMatch<Element>(null, null, vmI(IssueSeverity.INFORMATION, "No Display", "ValueSet.compose.include.concept")));
} }
return def;
} }
private void compareFilters(ConceptSetFilterComponent l, ConceptSetFilterComponent r, StructuralMatch<Element> sm, ConceptSetFilterComponent cu, ConceptSetFilterComponent ci) { private boolean compareFilters(ConceptSetFilterComponent l, ConceptSetFilterComponent r, StructuralMatch<Element> sm, ConceptSetFilterComponent cu, ConceptSetFilterComponent ci) {
sm.getChildren().add(new StructuralMatch<Element>(l.getPropertyElement(), r.getPropertyElement(), l.getProperty().equals(r.getProperty()) ? null : vmI(IssueSeverity.INFORMATION, "Properties do not match", "ValueSet.compose.include.concept"))); sm.getChildren().add(new StructuralMatch<Element>(l.getPropertyElement(), r.getPropertyElement(), l.getProperty().equals(r.getProperty()) ? null : vmI(IssueSeverity.INFORMATION, "Properties do not match", "ValueSet.compose.include.concept")));
sm.getChildren().add(new StructuralMatch<Element>(l.getOpElement(), r.getOpElement(), l.getOp().equals(r.getOp()) ? null : vmI(IssueSeverity.INFORMATION, "Filter Operations do not match", "ValueSet.compose.include.concept"))); sm.getChildren().add(new StructuralMatch<Element>(l.getOpElement(), r.getOpElement(), l.getOp().equals(r.getOp()) ? null : vmI(IssueSeverity.INFORMATION, "Filter Operations do not match", "ValueSet.compose.include.concept")));
sm.getChildren().add(new StructuralMatch<Element>(l.getValueElement(), r.getValueElement(), l.getValue().equals(r.getValue()) ? null : vmI(IssueSeverity.INFORMATION, "Values do not match", "ValueSet.compose.include.concept"))); sm.getChildren().add(new StructuralMatch<Element>(l.getValueElement(), r.getValueElement(), l.getValue().equals(r.getValue()) ? null : vmI(IssueSeverity.INFORMATION, "Values do not match", "ValueSet.compose.include.concept")));
@ -354,6 +393,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
cu.setOp(l.getOp()); cu.setOp(l.getOp());
cu.setValue(l.getValue()); cu.setValue(l.getValue());
} }
return !l.getProperty().equals(r.getProperty());
} }
private CanonicalType findInList(List<CanonicalType> matches, CanonicalType item, List<CanonicalType> source) { private CanonicalType findInList(List<CanonicalType> matches, CanonicalType item, List<CanonicalType> source) {

View File

@ -0,0 +1,146 @@
package org.hl7.fhir.r5.comparison;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class VersionComparisonAnnotation {
public enum AnotationType {
Added, Changed, Deleted;
}
public static final String USER_DATA_NAME = "version-annotation";
private AnotationType type;
// private String comment;
// private String link;
private Map<String, List<Base>> deletedChildren;
private String version;
private VersionComparisonAnnotation(AnotationType type, String version) {
super();
this.type = type;
this.version = version;
}
//
// private VersionComparisonAnnotation(AnotationType type, String comment) {
// super();
// this.type = type;
// this.comment = comment;
// }
// private VersionComparisonAnnotation(AnotationType type, String comment, String link) {
// super();
// this.type = type;
// this.comment = comment;
// this.link = link;
// }
//
public static void markAdded(Base focus, String version) {
focus.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Added, version));
}
public static void markDeleted(Base parent, String version, String name, Base other) {
VersionComparisonAnnotation vca = null;
if (parent.hasUserData(USER_DATA_NAME)) {
vca = (VersionComparisonAnnotation) parent.getUserData(USER_DATA_NAME);
assert vca.type != AnotationType.Added;
} else {
vca = new VersionComparisonAnnotation(AnotationType.Changed, version);
parent.setUserData(USER_DATA_NAME, vca);
}
if (vca.deletedChildren == null) {
vca.deletedChildren = new HashMap<>();
}
if (!vca.deletedChildren.containsKey(name)) {
vca.deletedChildren.put(name, new ArrayList<>());
}
other.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Deleted, version));
vca.deletedChildren.get(name).add(other);
}
public AnotationType getType() {
return type;
}
public void setType(AnotationType type) {
this.type = type;
}
// public String getComment() {
// return comment;
// }
// public void setComment(String comment) {
// this.comment = comment;
// }
// public String getLink() {
// return link;
// }
// public void setLink(String link) {
// this.link = link;
// }
public static XhtmlNode render(Base b, XhtmlNode x) {
if (b.hasUserData(USER_DATA_NAME)) {
VersionComparisonAnnotation self = (VersionComparisonAnnotation) b.getUserData(USER_DATA_NAME);
return self.render(x);
} else {
return x;
}
}
private XhtmlNode render(XhtmlNode x) {
switch (type) {
case Added:
XhtmlNode span = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
span.img("icon-change-add.png", "icon");
span.tx(" Added:");
return x;
case Changed:
span = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been changed since version "+version);
span.img("icon-change-edit.png", "icon");
span.tx(" Changed:");
return x;
case Deleted:
span = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been removed since version "+version);
span.img("icon-change-remove.png", "icon");
span.tx(" Removed:");
return x.strikethrough();
default:
return x;
}
}
public static boolean hasDeleted(Base base, String... names) {
boolean result = false;
if (base.hasUserData(USER_DATA_NAME)) {
VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
for (String name : names) {
if (self.deletedChildren != null && self.deletedChildren.containsKey(name)) {
result = true;
}
}
}
return result;
}
public static List<Base> getDeleted(Base base, String... names) {
List<Base> result = new ArrayList<>();
if (base.hasUserData(USER_DATA_NAME)) {
VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
for (String name : names) {
if (self.deletedChildren != null && self.deletedChildren.containsKey(name)) {
result.addAll(self.deletedChildren.get(name));
}
}
}
return result;
}
}

View File

@ -1521,6 +1521,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED); OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED);
iss.getDetails().setText(formatMessage(I18nConstants.MSG_RETIRED, ((PrimitiveType<?>) p.getValue()).asStringValue())); iss.getDetails().setText(formatMessage(I18nConstants.MSG_RETIRED, ((PrimitiveType<?>) p.getValue()).asStringValue()));
issues.add(iss); issues.add(iss);
} else if (p.getName().equals("warning-experimental")) {
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE);
iss.getDetails().setText(formatMessage(I18nConstants.MSG_EXPERIMENTAL, ((PrimitiveType<?>) p.getValue()).asStringValue()));
issues.add(iss);
} else if (p.getName().equals("warning-draft")) {
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.BUSINESSRULE);
iss.getDetails().setText(formatMessage(I18nConstants.MSG_DRAFT, ((PrimitiveType<?>) p.getValue()).asStringValue()));
issues.add(iss);
} else if (p.getName().equals("cause")) { } else if (p.getName().equals("cause")) {
try { try {
IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue()); IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue());

View File

@ -498,7 +498,11 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
for (PackageResourceInformation pri : pi.listIndexedResources(types)) { for (PackageResourceInformation pri : pi.listIndexedResources(types)) {
if (!pri.getFilename().contains("ig-r4") && (loader == null || loader.wantLoad(pi, pri))) { if (!pri.getFilename().contains("ig-r4") && (loader == null || loader.wantLoad(pi, pri))) {
try { try {
if (!pri.hasId()) {
loadDefinitionItem(pri.getFilename(), new FileInputStream(pri.getFilename()), loader, null, new PackageInformation(pi));
} else {
registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageInformation(pi)); registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageInformation(pi));
}
t++; t++;
} catch (FHIRException e) { } catch (FHIRException e) {
throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e); throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e);

View File

@ -28,6 +28,7 @@ import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.SourceLocation;
import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
@ -563,12 +564,14 @@ public class FmlParser extends ParserBase {
} }
private void parseParameter(Element ref, FHIRLexer lexer) throws FHIRLexerException, FHIRFormatError { private void parseParameter(Element ref, FHIRLexer lexer) throws FHIRLexerException, FHIRFormatError {
boolean r5 = VersionUtilities.isR5Plus(context.getVersion());
String name = r5 ? "parameter" : "variable";
if (!lexer.isConstant()) { if (!lexer.isConstant()) {
ref.addElement("parameter").markLocation(lexer.getCurrentLocation()).makeElement("valueId").setValue(lexer.take()); ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueId" : "value").setValue(lexer.take());
} else if (lexer.isStringConstant()) } else if (lexer.isStringConstant())
ref.addElement("parameter").markLocation(lexer.getCurrentLocation()).makeElement("valueString").setValue(lexer.readConstant("??")); ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueString" : "value").setValue(lexer.readConstant("??"));
else { else {
ref.addElement("parameter").markLocation(lexer.getCurrentLocation()).makeElement("valueString").setValue(readConstant(lexer.take(), lexer)); ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueString" : "value").setValue(readConstant(lexer.take(), lexer));
} }
} }

View File

@ -88,6 +88,17 @@ public abstract class Base implements Serializable, IBase, IElement {
} }
private static ThreadLocal<Boolean> copyUserData = new ThreadLocal<>();
public static boolean isCopyUserData() {
Boolean res = copyUserData.get();
return res != null && res;
}
public static void setCopyUserData(boolean value) {
copyUserData.set(value);
}
/** /**
* User appended data items - allow users to add extra information to the class * User appended data items - allow users to add extra information to the class
*/ */
@ -457,6 +468,10 @@ public abstract class Base implements Serializable, IBase, IElement {
public abstract Base copy(); public abstract Base copy();
public void copyValues(Base dst) { public void copyValues(Base dst) {
if (isCopyUserData() && userData != null) {
dst.userData = new HashMap<>();
dst.userData.putAll(userData);
}
} }
/** /**

View File

@ -14,8 +14,10 @@ import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation;
import org.hl7.fhir.r5.context.IWorkerContext.CodingValidationRequest; import org.hl7.fhir.r5.context.IWorkerContext.CodingValidationRequest;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.BooleanType; import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem;
@ -924,7 +926,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
generateCopyright(x, vs); generateCopyright(x, vs);
} }
int index = 0; int index = 0;
if (vs.getCompose().getInclude().size() == 1 && vs.getCompose().getExclude().size() == 0) { if (vs.getCompose().getInclude().size() == 1 && vs.getCompose().getExclude().size() == 0 && !VersionComparisonAnnotation.hasDeleted(vs.getCompose(), "include", "exclude")) {
hasExtensions = genInclude(x.ul(), vs.getCompose().getInclude().get(0), "Include", langs, doDesignations, maps, designations, index, vs) || hasExtensions; hasExtensions = genInclude(x.ul(), vs.getCompose().getInclude().get(0), "Include", langs, doDesignations, maps, designations, index, vs) || hasExtensions;
} else { } else {
XhtmlNode p = x.para(); XhtmlNode p = x.para();
@ -934,7 +936,11 @@ public class ValueSetRenderer extends TerminologyRenderer {
hasExtensions = genInclude(ul, inc, "Include", langs, doDesignations, maps, designations, index, vs) || hasExtensions; hasExtensions = genInclude(ul, inc, "Include", langs, doDesignations, maps, designations, index, vs) || hasExtensions;
index++; index++;
} }
if (vs.getCompose().hasExclude()) { for (Base inc : VersionComparisonAnnotation.getDeleted(vs.getCompose(), "include")) {
genInclude(ul, (ConceptSetComponent) inc, "Include", langs, doDesignations, maps, designations, index, vs);
index++;
}
if (vs.getCompose().hasExclude() || VersionComparisonAnnotation.hasDeleted(vs.getCompose(), "exclude")) {
p = x.para(); p = x.para();
p.tx("This value set excludes codes based on the following rules:"); p.tx("This value set excludes codes based on the following rules:");
ul = x.ul(); ul = x.ul();
@ -942,6 +948,10 @@ public class ValueSetRenderer extends TerminologyRenderer {
hasExtensions = genInclude(ul, exc, "Exclude", langs, doDesignations, maps, designations, index, vs) || hasExtensions; hasExtensions = genInclude(ul, exc, "Exclude", langs, doDesignations, maps, designations, index, vs) || hasExtensions;
index++; index++;
} }
for (Base inc : VersionComparisonAnnotation.getDeleted(vs.getCompose(), "exclude")) {
genInclude(ul, (ConceptSetComponent) inc, "Exclude", langs, doDesignations, maps, designations, index, vs);
index++;
}
} }
} }
@ -1131,6 +1141,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
boolean hasExtensions = false; boolean hasExtensions = false;
XhtmlNode li; XhtmlNode li;
li = ul.li(); li = ul.li();
li = VersionComparisonAnnotation.render(inc, li);
Map<String, ConceptDefinitionComponent> definitions = new HashMap<>(); Map<String, ConceptDefinitionComponent> definitions = new HashMap<>();
if (inc.hasSystem()) { if (inc.hasSystem()) {

View File

@ -97,6 +97,7 @@ import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r5.model.PrimitiveType; import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.CanonicalType; import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet;
@ -134,7 +135,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
private boolean includeAbstract = true; private boolean includeAbstract = true;
public ValueSetExpander(IWorkerContext context) { public ValueSetExpander(IWorkerContext context) {
super();
this.context = context; this.context = context;
} }
@ -149,7 +149,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
} }
private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, Parameters expParams, private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, Parameters expParams,
boolean isAbstract, boolean inactive, String definition, List<ValueSet> filters, boolean noInactive, boolean deprecated, List<ValueSetExpansionPropertyComponent> vsProp, boolean isAbstract, boolean inactive, List<ValueSet> filters, boolean noInactive, boolean deprecated, List<ValueSetExpansionPropertyComponent> vsProp,
List<ConceptPropertyComponent> csProps, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList, ValueSetExpansionComponent exp) throws ETooCostly { List<ConceptPropertyComponent> csProps, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList, ValueSetExpansionComponent exp) throws ETooCostly {
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp)) if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp))
@ -168,9 +168,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (deprecated) { if (deprecated) {
ValueSetUtilities.setDeprecated(vsProp, n); ValueSetUtilities.setDeprecated(vsProp, n);
} }
if (expParams.getParameterBool("includeDefinition") && definition != null) {
n.addExtension(Extensions.makeVSConceptDefinition(definition));
}
if (ExtensionsUtils.hasExtension(csExtList, "http://hl7.org/fhir/StructureDefinition/codesystem-label")) { if (ExtensionsUtils.hasExtension(csExtList, "http://hl7.org/fhir/StructureDefinition/codesystem-label")) {
ValueSetUtilities.addProperty(focus, n, "http://hl7.org/fhir/concept-properties#label", "label", ExtensionsUtils.getExtensionValue(csExtList, "http://hl7.org/fhir/StructureDefinition/codesystem-label")); ValueSetUtilities.addProperty(focus, n, "http://hl7.org/fhir/concept-properties#label", "label", ExtensionsUtils.getExtensionValue(csExtList, "http://hl7.org/fhir/StructureDefinition/codesystem-label"));
} }
@ -286,7 +283,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private boolean filterContainsCode(List<ValueSet> filters, String system, String code, ValueSetExpansionComponent exp) { private boolean filterContainsCode(List<ValueSet> filters, String system, String code, ValueSetExpansionComponent exp) {
for (ValueSet vse : filters) { for (ValueSet vse : filters) {
checkCanonical(exp, vse); checkCanonical(exp, vse, focus);
if (expansionContainsCode(vse.getExpansion().getContains(), system, code)) if (expansionContainsCode(vse.getExpansion().getContains(), system, code))
return true; return true;
} }
@ -318,7 +315,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
ValueSetExpansionContainsComponent np = null; ValueSetExpansionContainsComponent np = null;
for (String code : getCodesForConcept(focus, expParams)) { for (String code : getCodesForConcept(focus, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, focus.getSystem(), code, focus.getDisplay(), vsSrc.getLanguage(), parent, ValueSetExpansionContainsComponent t = addCode(wc, focus.getSystem(), code, focus.getDisplay(), vsSrc.getLanguage(), parent,
convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), filters, noInactive, false, vsProps, null, focus.getProperty(), null, focus.getExtension(), exp); convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), filters, noInactive, false, vsProps, makeCSProps(focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), null), focus.getProperty(), null, focus.getExtension(), exp);
if (np == null) { if (np == null) {
np = t; np = t;
} }
@ -327,6 +324,17 @@ public class ValueSetExpander extends ValueSetProcessBase {
addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc, exp); addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc, exp);
} }
private List<ConceptPropertyComponent> makeCSProps(String definition, List<ConceptPropertyComponent> list) {
List<ConceptPropertyComponent> res = new ArrayList<>();
if (!Utilities.noString(definition)) {
res.add(new ConceptPropertyComponent("definition", new StringType(definition)));
}
if (list != null) {
res.addAll(list);
}
return res;
}
private List<String> getCodesForConcept(ValueSetExpansionContainsComponent focus, Parameters expParams) { private List<String> getCodesForConcept(ValueSetExpansionContainsComponent focus, Parameters expParams) {
List<String> codes = new ArrayList<>(); List<String> codes = new ArrayList<>();
codes.add(focus.getCode()); codes.add(focus.getCode());
@ -363,7 +371,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
boolean dep = CodeSystemUtilities.isDeprecated(cs, def, false); boolean dep = CodeSystemUtilities.isDeprecated(cs, def, false);
if ((includeAbstract || !abs) && filterFunc.includeConcept(cs, def) && passesOtherFilters(otherFilters, cs, def.getCode())) { if ((includeAbstract || !abs) && filterFunc.includeConcept(cs, def) && passesOtherFilters(otherFilters, cs, def.getCode())) {
for (String code : getCodesForConcept(def, expParams)) { for (String code : getCodesForConcept(def, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, def.getDefinition(), filters, noInactive, dep, vsProps, def.getProperty(), null, def.getExtension(), null, exp); ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, filters, noInactive, dep, vsProps, makeCSProps(def.getDefinition(), def.getProperty()), null, def.getExtension(), null, exp);
if (np == null) { if (np == null) {
np = t; np = t;
} }
@ -503,7 +511,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
focus.setExpansion(new ValueSet.ValueSetExpansionComponent()); focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
focus.getExpansion().setTimestampElement(DateTimeType.now()); focus.getExpansion().setTimestampElement(DateTimeType.now());
focus.getExpansion().setIdentifier(Factory.createUUID()); focus.getExpansion().setIdentifier(Factory.createUUID());
checkCanonical(focus.getExpansion(), focus); checkCanonical(focus.getExpansion(), focus, focus);
for (ParametersParameterComponent p : expParams.getParameter()) { for (ParametersParameterComponent p : expParams.getParameter()) {
if (Utilities.existsInList(p.getName(), "includeDesignations", "excludeNested", "activeOnly", "offset", "count")) { if (Utilities.existsInList(p.getName(), "includeDesignations", "excludeNested", "activeOnly", "offset", "count")) {
focus.getExpansion().addParameter().setName(p.getName()).setValue(p.getValue()); focus.getExpansion().addParameter().setName(p.getName()).setValue(p.getValue());
@ -643,7 +651,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
throw fail("Unable to find imported value set " + value); throw fail("Unable to find imported value set " + value);
} }
} }
checkCanonical(exp, vs); checkCanonical(exp, vs, focus);
if (noInactive) { if (noInactive) {
expParams = expParams.copy(); expParams = expParams.copy();
expParams.addParameter("activeOnly", true); expParams.addParameter("activeOnly", true);
@ -719,8 +727,8 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly { private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
for (ValueSetExpansionContainsComponent c : list) { for (ValueSetExpansionContainsComponent c : list) {
c.checkNoModifiers("Imported Expansion in Code System", "expanding"); c.checkNoModifiers("Imported Expansion in Code System", "expanding");
ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(), c.getExtensionString(ToolingExtensions.EXT_DEFINITION), ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(),
filter, noInactive, false, vsProps, null, c.getProperty(), null, c.getExtension(), exp); filter, noInactive, false, vsProps, makeCSProps(c.getExtensionString(ToolingExtensions.EXT_DEFINITION), null), c.getProperty(), null, c.getExtension(), exp);
copyImportContains(c.getContains(), np, expParams, filter, noInactive, vsProps, vsSrc, exp); copyImportContains(c.getContains(), np, expParams, filter, noInactive, vsProps, vsSrc, exp);
} }
} }
@ -736,7 +744,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (imports.isEmpty()) // though this is not supposed to be the case if (imports.isEmpty()) // though this is not supposed to be the case
return; return;
ValueSet base = imports.get(0); ValueSet base = imports.get(0);
checkCanonical(exp, base); checkCanonical(exp, base, focus);
imports.remove(0); imports.remove(0);
base.checkNoModifiers("Imported ValueSet", "expanding"); base.checkNoModifiers("Imported ValueSet", "expanding");
copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base, exp); copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base, exp);
@ -798,7 +806,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
else else
throw failTSE("Unable to find code system " + inc.getSystem().toString()); throw failTSE("Unable to find code system " + inc.getSystem().toString());
} }
checkCanonical(exp, cs); checkCanonical(exp, cs, focus);
cs.checkNoModifiers("Code System", "expanding"); cs.checkNoModifiers("Code System", "expanding");
if (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT) if (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)
throw failTSE("Code system " + inc.getSystem().toString() + " is incomplete"); throw failTSE("Code system " + inc.getSystem().toString() + " is incomplete");
@ -850,7 +858,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
isAbstract = CodeSystemUtilities.isNotSelectable(cs, def); isAbstract = CodeSystemUtilities.isNotSelectable(cs, def);
} }
addCode(dwc, inc.getSystem(), c.getCode(), !Utilities.noString(c.getDisplay()) ? c.getDisplay() : def == null ? null : def.getDisplay(), c.hasDisplay() ? vsSrc.getLanguage() : cs.getLanguage(), null, mergeDesignations(def, convertDesignations(c.getDesignation())), addCode(dwc, inc.getSystem(), c.getCode(), !Utilities.noString(c.getDisplay()) ? c.getDisplay() : def == null ? null : def.getDisplay(), c.hasDisplay() ? vsSrc.getLanguage() : cs.getLanguage(), null, mergeDesignations(def, convertDesignations(c.getDesignation())),
expParams, isAbstract, inactive, def == null ? null : def.getDefinition(), imports, noInactive, false, exp.getProperty(), def != null ? def.getProperty() : null, null, def == null ? null : def.getExtension(), c.getExtension(), exp); expParams, isAbstract, inactive, imports, noInactive, false, exp.getProperty(), def == null ? null : makeCSProps(def.getDefinition(), def.getProperty()), null, def == null ? null : def.getExtension(), c.getExtension(), exp);
} }
} }
if (inc.getFilter().size() > 0) { if (inc.getFilter().size() > 0) {
@ -911,7 +919,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (def.getDisplay().contains(fc.getValue()) && passesOtherFilters(filters, cs, def.getCode())) { if (def.getDisplay().contains(fc.getValue()) && passesOtherFilters(filters, cs, def.getCode())) {
for (String code : getCodesForConcept(def, expParams)) { for (String code : getCodesForConcept(def, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def), ValueSetExpansionContainsComponent t = addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
def.getDefinition(), imports, noInactive, false, exp.getProperty(), def.getProperty(), null, def.getExtension(), null, exp); imports, noInactive, false, exp.getProperty(), makeCSProps(def.getDefinition(), def.getProperty()), null, def.getExtension(), null, exp);
} }
} }
} }

View File

@ -113,7 +113,7 @@ public class ValueSetProcessBase {
return list; return list;
} }
public void checkCanonical(List<OperationOutcomeIssueComponent> issues, String path, CanonicalResource resource) { public void checkCanonical(List<OperationOutcomeIssueComponent> issues, String path, CanonicalResource resource, CanonicalResource source) {
if (resource != null) { if (resource != null) {
StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource); StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
if (standardsStatus == StandardsStatus.DEPRECATED) { if (standardsStatus == StandardsStatus.DEPRECATED) {
@ -122,6 +122,13 @@ public class ValueSetProcessBase {
addToIssues(issues, makeStatusIssue(path, "withdrawn", I18nConstants.MSG_WITHDRAWN, resource)); addToIssues(issues, makeStatusIssue(path, "withdrawn", I18nConstants.MSG_WITHDRAWN, resource));
} else if (resource.getStatus() == PublicationStatus.RETIRED) { } else if (resource.getStatus() == PublicationStatus.RETIRED) {
addToIssues(issues, makeStatusIssue(path, "retired", I18nConstants.MSG_RETIRED, resource)); addToIssues(issues, makeStatusIssue(path, "retired", I18nConstants.MSG_RETIRED, resource));
} else if (source != null) {
if (resource.getExperimental() && !source.getExperimental()) {
addToIssues(issues, makeStatusIssue(path, "experimental", I18nConstants.MSG_EXPERIMENTAL, resource));
} else if ((resource.getStatus() == PublicationStatus.DRAFT || standardsStatus == StandardsStatus.DRAFT)
&& !(source.getStatus() == PublicationStatus.DRAFT || ToolingExtensions.getStandardsStatus(source) == StandardsStatus.DRAFT)) {
addToIssues(issues, makeStatusIssue(path, "draft", I18nConstants.MSG_DRAFT, resource));
}
} }
} }
} }
@ -150,7 +157,7 @@ public class ValueSetProcessBase {
} }
} }
public void checkCanonical(ValueSetExpansionComponent params, CanonicalResource resource) { public void checkCanonical(ValueSetExpansionComponent params, CanonicalResource resource, ValueSet source) {
if (resource != null) { if (resource != null) {
StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource); StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
if (standardsStatus == StandardsStatus.DEPRECATED) { if (standardsStatus == StandardsStatus.DEPRECATED) {
@ -165,6 +172,15 @@ public class ValueSetProcessBase {
if (!params.hasParameterValue("warning-retired", resource.getVersionedUrl())) { if (!params.hasParameterValue("warning-retired", resource.getVersionedUrl())) {
params.addParameter("warning-retired", new UriType(resource.getVersionedUrl())); params.addParameter("warning-retired", new UriType(resource.getVersionedUrl()));
} }
} else if (resource.getExperimental() && !source.getExperimental()) {
if (!params.hasParameterValue("warning-experimental", resource.getVersionedUrl())) {
params.addParameter("warning-experimental", new UriType(resource.getVersionedUrl()));
}
} else if ((resource.getStatus() == PublicationStatus.DRAFT || standardsStatus == StandardsStatus.DRAFT)
&& !(source.getStatus() == PublicationStatus.DRAFT || ToolingExtensions.getStandardsStatus(source) == StandardsStatus.DRAFT)) {
if (!params.hasParameterValue("warning-draft", resource.getVersionedUrl())) {
params.addParameter("warning-draft", new UriType(resource.getVersionedUrl()));
}
} }
} }
} }

View File

@ -351,7 +351,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
ValidationProcessInfo info = new ValidationProcessInfo(issues); ValidationProcessInfo info = new ValidationProcessInfo(issues);
VersionInfo vi = new VersionInfo(this); VersionInfo vi = new VersionInfo(this);
checkCanonical(issues, path, valueset); checkCanonical(issues, path, valueset, valueset);
String system = code.hasSystem() ? code.getSystem() : getValueSetSystemOrNull(); String system = code.hasSystem() ? code.getSystem() : getValueSetSystemOrNull();
if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) { if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) {
@ -412,7 +412,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
} }
} }
} else { } else {
checkCanonical(issues, path, cs); checkCanonical(issues, path, cs, valueset);
} }
if (cs != null && cs.hasSupplements()) { if (cs != null && cs.hasSupplements()) {
String msg = context.formatMessage(I18nConstants.CODESYSTEM_CS_NO_SUPPLEMENT, cs.getUrl()); String msg = context.formatMessage(I18nConstants.CODESYSTEM_CS_NO_SUPPLEMENT, cs.getUrl());
@ -975,7 +975,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (valueset == null) { if (valueset == null) {
return false; return false;
} }
checkCanonical(info.getIssues(), path, valueset); checkCanonical(info.getIssues(), path, valueset, valueset);
Boolean result = false; Boolean result = false;
VersionInfo vi = new VersionInfo(this); VersionInfo vi = new VersionInfo(this);
@ -1083,7 +1083,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
return null; return null;
} }
} else { } else {
checkCanonical(info.getIssues(), path, cs); checkCanonical(info.getIssues(), path, cs, valueset);
if (valueset.getCompose().hasInactive() && !valueset.getCompose().getInactive()) { if (valueset.getCompose().hasInactive() && !valueset.getCompose().getInactive()) {
if (CodeSystemUtilities.isInactive(cs, code)) { if (CodeSystemUtilities.isInactive(cs, code)) {
return false; return false;

View File

@ -309,7 +309,7 @@ public class CompareUtilities extends BaseTestingUtilities {
int expectedMin = countExpectedMin(expectedArray); int expectedMin = countExpectedMin(expectedArray);
if (actualArray.size() > expectedArray.size() || actualArray.size() < expectedMin) if (actualArray.size() > expectedArray.size() || actualArray.size() < expectedMin)
return createNotEqualMessage("array properties count differs at " + path, Integer.toString(expectedArray.size()), Integer.toString(actualArray.size())); return createNotEqualMessage("array item count differs at " + path, Integer.toString(expectedArray.size()), Integer.toString(actualArray.size()));
int c = 0; int c = 0;
for (int i = 0; i < expectedArray.size(); i++) { for (int i = 0; i < expectedArray.size(); i++) {
if (c >= actualArray.size()) { if (c >= actualArray.size()) {

View File

@ -8,8 +8,8 @@ import org.hl7.fhir.r5.model.Resource;
public class ElementVisitor { public class ElementVisitor {
public interface IElementVisitor { public interface IElementVisitor {
public void visit(Resource resource); public void visit(Object context, Resource resource);
public void visit(Element element); public void visit(Object context, Element element);
} }
private IElementVisitor visitor; private IElementVisitor visitor;
@ -18,28 +18,28 @@ public class ElementVisitor {
this.visitor = visitor; this.visitor = visitor;
} }
private void visitBase(Base base) { private void visitBase(Object context, Base base) {
for (Property p : base.children()) { for (Property p : base.children()) {
if (p.hasValues()) { if (p.hasValues()) {
for (Base b : p.getValues()) { for (Base b : p.getValues()) {
if (b instanceof Resource) { if (b instanceof Resource) {
visit((Resource) b); visit(context, (Resource) b);
} else { } else {
visit((Element) b); visit(context, (Element) b);
} }
} }
} }
} }
} }
public void visit(Resource res) { public void visit(Object context, Resource res) {
visitor.visit(res); visitor.visit(context, res);
visitBase(res); visitBase(context, res);
} }
public void visit(Element e) { public void visit(Object context, Element e) {
visitor.visit(e); visitor.visit(context, e);
visitBase(e); visitBase(context, e);
} }
} }

View File

@ -6325,7 +6325,6 @@ public class FHIRPathEngine {
SourcedChildDefinitions childDefinitions = profileUtilities.getChildMap(sd, element.getElement()); SourcedChildDefinitions childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
for (ElementDefinition t : childDefinitions.getList()) { for (ElementDefinition t : childDefinitions.getList()) {
if (t.getPath().endsWith(".extension") && t.hasSliceName()) { if (t.getPath().endsWith(".extension") && t.hasSliceName()) {
System.out.println("t: "+t.getId());
StructureDefinition exsd = (t.getType() == null || t.getType().isEmpty() || t.getType().get(0).getProfile().isEmpty()) ? StructureDefinition exsd = (t.getType() == null || t.getType().isEmpty() || t.getType().get(0).getProfile().isEmpty()) ?
null : worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue(), profile); null : worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue(), profile);
while (exsd != null && !exsd.getBaseDefinition().equals("http://hl7.org/fhir/StructureDefinition/Extension")) { while (exsd != null && !exsd.getBaseDefinition().equals("http://hl7.org/fhir/StructureDefinition/Extension")) {

View File

@ -112,6 +112,7 @@ public class FHIRToolingClient {
public void initialize(String baseServiceUrl) throws URISyntaxException { public void initialize(String baseServiceUrl) throws URISyntaxException {
base = baseServiceUrl; base = baseServiceUrl;
client.setBase(base);
resourceAddress = new ResourceAddress(baseServiceUrl); resourceAddress = new ResourceAddress(baseServiceUrl);
this.maxResultSetSize = -1; this.maxResultSetSize = -1;
} }

View File

@ -23,6 +23,15 @@ public class Client {
private int retryCount; private int retryCount;
private long timeout = DEFAULT_TIMEOUT; private long timeout = DEFAULT_TIMEOUT;
private byte[] payload; private byte[] payload;
private String base;
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public ToolingClientLogger getLogger() { public ToolingClientLogger getLogger() {
return logger; return logger;
@ -174,7 +183,7 @@ public class Client {
String message, String message,
int retryCount, int retryCount,
long timeout) throws IOException { long timeout) throws IOException {
return new FhirRequestBuilder(request) return new FhirRequestBuilder(request, base)
.withLogger(fhirLoggingInterceptor) .withLogger(fhirLoggingInterceptor)
.withResourceFormat(resourceFormat) .withResourceFormat(resourceFormat)
.withRetryCount(retryCount) .withRetryCount(retryCount)
@ -190,7 +199,7 @@ public class Client {
String message, String message,
int retryCount, int retryCount,
long timeout) throws IOException { long timeout) throws IOException {
return new FhirRequestBuilder(request) return new FhirRequestBuilder(request, base)
.withLogger(fhirLoggingInterceptor) .withLogger(fhirLoggingInterceptor)
.withResourceFormat(resourceFormat) .withResourceFormat(resourceFormat)
.withRetryCount(retryCount) .withRetryCount(retryCount)

View File

@ -50,9 +50,11 @@ public class FhirRequestBuilder {
* {@link FhirLoggingInterceptor} for log output. * {@link FhirLoggingInterceptor} for log output.
*/ */
private FhirLoggingInterceptor logger = null; private FhirLoggingInterceptor logger = null;
private String source;
public FhirRequestBuilder(Request.Builder httpRequest) { public FhirRequestBuilder(Request.Builder httpRequest, String source) {
this.httpRequest = httpRequest; this.httpRequest = httpRequest;
this.source = source;
} }
/** /**
@ -249,14 +251,14 @@ public class FhirRequestBuilder {
error = (OperationOutcome) resource; error = (OperationOutcome) resource;
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response: " + ioe.getMessage(), ioe); throw new EFhirClientException("Error reading Http Response from "+source+": " + ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message: " + e.getMessage(), e); throw new EFhirClientException("Error parsing response message from "+source+": " + e.getMessage(), e);
} }
} }
if (error != null) { if (error != null) {
throw new EFhirClientException("Error from server: " + ResourceUtilities.getErrorDescription(error), error); throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} }
return resource; return resource;
@ -284,12 +286,12 @@ public class FhirRequestBuilder {
} }
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response", ioe); throw new EFhirClientException("Error reading Http Response from "+source+":"+ioe.getMessage(), ioe);
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message", e); throw new EFhirClientException("Error parsing response message from "+source+": "+e.getMessage(), e);
} }
if (error != null) { if (error != null) {
throw new EFhirClientException("Error from server: " + ResourceUtilities.getErrorDescription(error), error); throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} }
return feed; return feed;
} }

View File

@ -102,6 +102,10 @@ public interface IResourceValidator {
boolean isForPublication(); boolean isForPublication();
IResourceValidator setForPublication(boolean forPublication); IResourceValidator setForPublication(boolean forPublication);
public boolean isWarnOnDraftOrExperimental();
public IResourceValidator setWarnOnDraftOrExperimental(boolean warnOnDraftOrExperimental);
/** /**
* 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 * 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
*/ */

View File

@ -28,7 +28,6 @@ public class PEModelTest1343 {
} }
} }
@Test @Test
public void testPatientCreate() throws Exception { public void testPatientCreate() throws Exception {
CreatePatientFromProfile("http://interopsante.org/fhir/StructureDefinition/FrPatient"); CreatePatientFromProfile("http://interopsante.org/fhir/StructureDefinition/FrPatient");

View File

@ -1,3 +1,3 @@
array properties count differs at .expectedArray array item count differs at .expectedArray
Expected :2 Expected :2
Actual :1 Actual :1

View File

@ -956,6 +956,15 @@ public class I18nConstants {
public static final String MSG_RETIRED = "MSG_RETIRED"; public static final String MSG_RETIRED = "MSG_RETIRED";
public static final String INACTIVE_CODE_WARNING = "INACTIVE_CODE_WARNING"; public static final String INACTIVE_CODE_WARNING = "INACTIVE_CODE_WARNING";
public static final String SD_EXTENSION_URL_MISSING = "SD_EXTENSION_URL_MISSING"; public static final String SD_EXTENSION_URL_MISSING = "SD_EXTENSION_URL_MISSING";
public static final String MSG_EXPERIMENTAL = "MSG_EXPERIMENTAL";
public static final String MSG_DRAFT = "MSG_DRAFT";
public static final String MSG_DEPENDS_ON_DEPRECATED = "MSG_DEPENDS_ON_DEPRECATED";
public static final String MSG_DEPENDS_ON_WITHDRAWN = "MSG_DEPENDS_ON_WITHDRAWN";
public static final String MSG_DEPENDS_ON_RETIRED = "MSG_DEPENDS_ON_RETIRED";
public static final String MSG_DEPENDS_ON_EXPERIMENTAL = "MSG_DEPENDS_ON_EXPERIMENTAL";
public static final String MSG_DEPENDS_ON_DRAFT = "MSG_DEPENDS_ON_DRAFT";
public static final String MSG_DEPENDS_ON_EXTENSION = "MSG_DEPENDS_ON_EXTENSION";
public static final String MSG_DEPENDS_ON_PROFILE = "MSG_DEPENDS_ON_PROFILE";
} }

View File

@ -144,6 +144,9 @@ public class NpmPackage {
public String getSupplements() { public String getSupplements() {
return supplements; return supplements;
} }
public boolean hasId() {
return !Utilities.noString(id);
}
} }
public class IndexVersionSorter implements Comparator<JsonObject> { public class IndexVersionSorter implements Comparator<JsonObject> {

View File

@ -867,4 +867,9 @@ public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
return res; return res;
} }
public XhtmlNode strikethrough() {
return addTag("s");
}
} }

View File

@ -1012,5 +1012,14 @@ SD_EXTENSION_URL_MISSING = The value of Extension.url is not fixed to the extens
MSG_DEPRECATED = Reference to deprecated item {0} MSG_DEPRECATED = Reference to deprecated item {0}
MSG_WITHDRAWN = Reference to withdrawn item {0} MSG_WITHDRAWN = Reference to withdrawn item {0}
MSG_RETIRED = Reference to retired item {0} MSG_RETIRED = Reference to retired item {0}
MSG_EXPERIMENTAL = Reference to experimental item {0}
MSG_DRAFT = Reference to draft item {0}
INACTIVE_CODE_WARNING = The code ''{0}'' is valid but is not active INACTIVE_CODE_WARNING = The code ''{0}'' is valid but is not active
SD_ED_TYPE_PROFILE_WRONG_TYPE = The type {0} is not in the list of allowed types {1} in the profile {2} SD_ED_TYPE_PROFILE_WRONG_TYPE = The type {0} is not in the list of allowed types {1} in the profile {2}
MSG_DEPENDS_ON_DEPRECATED = The {0} {1} is deprecated
MSG_DEPENDS_ON_WITHDRAWN = The {0} {1} is withdrawn
MSG_DEPENDS_ON_RETIRED = The {0} {1} is retired
MSG_DEPENDS_ON_EXPERIMENTAL = The {0} {1} is an experimental resource
MSG_DEPENDS_ON_DRAFT = The {0} {1} is a draft resource
MSG_DEPENDS_ON_EXTENSION = extension
MSG_DEPENDS_ON_PROFILE = profile

View File

@ -7,8 +7,10 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/* /*
Copyright (c) 2011+, HL7, Inc. Copyright (c) 2011+, HL7, Inc.
@ -51,16 +53,20 @@ import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.JsonParser; import org.hl7.fhir.r5.elementmodel.JsonParser;
import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.terminologies.ValueSetUtilities; import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus; import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader;
import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.StandardsStatus;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
@ -144,18 +150,20 @@ public class BaseValidator implements IValidationContextResourceLoader {
protected final String BUNDLE = "Bundle"; protected final String BUNDLE = "Bundle";
protected final String LAST_UPDATED = "lastUpdated"; protected final String LAST_UPDATED = "lastUpdated";
protected BaseValidator parent;
protected Source source; protected Source source;
protected IWorkerContext context; protected IWorkerContext context;
protected TimeTracker timeTracker = new TimeTracker(); protected TimeTracker timeTracker = new TimeTracker();
protected XVerExtensionManager xverManager; protected XVerExtensionManager xverManager;
protected List<TrackedLocationRelatedMessage> trackedMessages = new ArrayList<>(); protected List<TrackedLocationRelatedMessage> trackedMessages = new ArrayList<>();
protected List<ValidationMessage> messagesToRemove = new ArrayList<>(); protected List<ValidationMessage> messagesToRemove = new ArrayList<>();
private ValidationLevel level = ValidationLevel.HINTS; protected ValidationLevel level = ValidationLevel.HINTS;
protected Coding jurisdiction; protected Coding jurisdiction;
protected boolean allowExamples; protected boolean allowExamples;
protected boolean forPublication; protected boolean forPublication;
protected boolean debug; protected boolean debug;
protected boolean warnOnDraftOrExperimental;
protected Set<String> statusWarnings = new HashSet<>();
public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug) { public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug) {
super(); super();
@ -167,6 +175,24 @@ public class BaseValidator implements IValidationContextResourceLoader {
this.debug = debug; this.debug = debug;
} }
public BaseValidator(BaseValidator parent) {
super();
this.parent = parent;
this.context = parent.context;
this.xverManager = parent.xverManager;
this.debug = parent.debug;
this.source = parent.source;
this.timeTracker = parent.timeTracker;
this.trackedMessages = parent.trackedMessages;
this.messagesToRemove = parent.messagesToRemove;
this.level = parent.level;
this.allowExamples = parent.allowExamples;
this.forPublication = parent.forPublication;
this.debug = parent.debug;
this.warnOnDraftOrExperimental = parent.warnOnDraftOrExperimental;
this.statusWarnings = parent.statusWarnings;
}
private boolean doingLevel(IssueSeverity error) { private boolean doingLevel(IssueSeverity error) {
switch (error) { switch (error) {
case ERROR: case ERROR:
@ -1278,4 +1304,41 @@ public class BaseValidator implements IValidationContextResourceLoader {
this.debug = debug; this.debug = debug;
} }
protected void checkDefinitionStatus(List<ValidationMessage> errors, Element element, String path, StructureDefinition ex, CanonicalResource source, String type) {
String vurl = ex.getVersionedUrl();
StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(ex);
if (standardsStatus == StandardsStatus.DEPRECATED) {
if (!statusWarnings.contains(vurl+":DEPRECATED")) {
statusWarnings.add(vurl+":DEPRECATED");
hint(errors, "2023-08-10", IssueType.EXPIRED, element.line(), element.col(), path, false, I18nConstants.MSG_DEPENDS_ON_DEPRECATED, type, vurl);
}
} else if (standardsStatus == StandardsStatus.WITHDRAWN) {
if (!statusWarnings.contains(vurl+":WITHDRAWN")) {
statusWarnings.add(vurl+":WITHDRAWN");
hint(errors, "2023-08-10", IssueType.EXPIRED, element.line(), element.col(), path, false, I18nConstants.MSG_DEPENDS_ON_WITHDRAWN, type, vurl);
}
} else if (ex.getStatus() == PublicationStatus.RETIRED) {
if (!statusWarnings.contains(vurl+":RETIRED")) {
statusWarnings.add(vurl+":RETIRED");
hint(errors, "2023-08-10", IssueType.EXPIRED, element.line(), element.col(), path, false, I18nConstants.MSG_DEPENDS_ON_RETIRED, type, vurl);
}
} else if (false && warnOnDraftOrExperimental && source != null) {
// for now, this is disabled; these warnings are just everywhere, and it's an intractible problem.
// working this through QA in IG publisher
if (ex.getExperimental() && !source.getExperimental()) {
if (!statusWarnings.contains(vurl+":Experimental")) {
statusWarnings.add(vurl+":Experimental");
hint(errors, "2023-08-10", IssueType.BUSINESSRULE, element.line(), element.col(), path, false, I18nConstants.MSG_DEPENDS_ON_EXPERIMENTAL, type, vurl);
}
} else if (ex.getStatus() == PublicationStatus.DRAFT && source.getStatus() != PublicationStatus.DRAFT) {
if (!statusWarnings.contains(vurl+":Draft")) {
statusWarnings.add(vurl+":Draft");
hint(errors, "2023-08-10", IssueType.BUSINESSRULE, element.line(), element.col(), path, false, I18nConstants.MSG_DEPENDS_ON_DRAFT, type, vurl);
}
}
}
}
} }

View File

@ -101,6 +101,8 @@ public class CliContext {
private List<String> sources = new ArrayList<String>(); private List<String> sources = new ArrayList<String>();
@JsonProperty("inputs") @JsonProperty("inputs")
private List<String> inputs = new ArrayList<String>(); private List<String> inputs = new ArrayList<String>();
@JsonProperty("modeParams")
private List<String> modeParams = new ArrayList<String>();
@JsonProperty("mode") @JsonProperty("mode")
private EngineMode mode = EngineMode.VALIDATION; private EngineMode mode = EngineMode.VALIDATION;
@ -428,6 +430,12 @@ public class CliContext {
return inputs; return inputs;
} }
@JsonProperty("modeParams")
public List<String> getModeParams() {
return modeParams;
}
@JsonProperty("sources") @JsonProperty("sources")
public CliContext setSources(List<String> sources) { public CliContext setSources(List<String> sources) {
this.sources = sources; this.sources = sources;

View File

@ -41,7 +41,7 @@ public class TxTestsTask extends StandaloneTask{
final String version = Params.getParam(args, Params.VERSION); final String version = Params.getParam(args, Params.VERSION);
final String tx = Params.getParam(args, Params.TERMINOLOGY); final String tx = Params.getParam(args, Params.TERMINOLOGY);
final String filter = Params.getParam(args, Params.FILTER); final String filter = Params.getParam(args, Params.FILTER);
boolean ok = new TxTester(new TxTester.InternalTxLoader(source, output), tx, false).setOutput(output).execute(version, filter); boolean ok = new TxTester(new TxTester.InternalTxLoader(source, output), tx, false).setOutput(output).execute(version, cliContext.getModeParams(), filter);
SystemExitManager.setError(ok ? 1 : 0); SystemExitManager.setError(ok ? 1 : 0);
SystemExitManager.finish(); SystemExitManager.finish();
} }

View File

@ -99,6 +99,7 @@ public class Params {
public static final String SOURCE = "-source"; public static final String SOURCE = "-source";
public static final String INPUT = "-input"; public static final String INPUT = "-input";
public static final String FILTER = "-filter"; public static final String FILTER = "-filter";
public static final String MODE = "-mode";
private static final String FHIR_SETTINGS_PARAM = "-fhir-settings"; private static final String FHIR_SETTINGS_PARAM = "-fhir-settings";
private static final String WATCH_MODE_PARAM = "-watch-mode"; private static final String WATCH_MODE_PARAM = "-watch-mode";
private static final String WATCH_SCAN_DELAY = "-watch-scan-delay"; private static final String WATCH_SCAN_DELAY = "-watch-scan-delay";
@ -203,6 +204,13 @@ public class Params {
String q = args[++i]; String q = args[++i];
cliContext.setLevel(ValidationLevel.fromCode(q)); cliContext.setLevel(ValidationLevel.fromCode(q));
} }
} else if (args[i].equals(MODE)) {
if (i + 1 == args.length)
throw new Error("Specified -mode without indicating mode");
else {
String q = args[++i];
cliContext.getModeParams().add(q);
}
} else if (args[i].equals(INPUT)) { } else if (args[i].equals(INPUT)) {
if (i + 1 == args.length) if (i + 1 == args.length)
throw new Error("Specified -input without providing value"); throw new Error("Specified -input without providing value");

View File

@ -52,6 +52,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Stack;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -114,6 +115,7 @@ import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.Enumeration; import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Enumerations.BindingStrength; import org.hl7.fhir.r5.model.Enumerations.BindingStrength;
import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode; import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.ExpressionNode; import org.hl7.fhir.r5.model.ExpressionNode;
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus; import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.Extension;
@ -171,6 +173,7 @@ import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor; import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.SIDUtilities; import org.hl7.fhir.utilities.SIDUtilities;
import org.hl7.fhir.utilities.StandardsStatus;
import org.hl7.fhir.utilities.UnicodeUtilities; import org.hl7.fhir.utilities.UnicodeUtilities;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.Utilities.DecimalStatus; import org.hl7.fhir.utilities.Utilities.DecimalStatus;
@ -1938,9 +1941,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else { } else {
rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", def.getIsModifier() == isModifier, I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHN); rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", def.getIsModifier() == isModifier, I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHN);
} }
// two questions
// 1. can this extension be used here? // 1. can this extension be used here?
checkExtensionContext(hostContext.getAppContext(), errors, resource, container, ex, containerStack, hostContext, isModifier); checkExtensionContext(hostContext.getAppContext(), errors, resource, container, ex, containerStack, hostContext, isModifier);
checkDefinitionStatus(errors, element, path, ex, profile, context.formatMessage(I18nConstants.MSG_DEPENDS_ON_EXTENSION));
if (isModifier) if (isModifier)
rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", ex.getSnapshot().getElement().get(0).getIsModifier(), I18nConstants.EXTENSION_EXT_MODIFIER_Y, url); rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", ex.getSnapshot().getElement().get(0).getIsModifier(), I18nConstants.EXTENSION_EXT_MODIFIER_Y, url);
@ -1964,8 +1968,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return ex; return ex;
} }
private boolean hasExtensionSlice(StructureDefinition profile, String sliceName) { private boolean hasExtensionSlice(StructureDefinition profile, String sliceName) {
for (ElementDefinition ed : profile.getSnapshot().getElement()) { for (ElementDefinition ed : profile.getSnapshot().getElement()) {
if (ed.getPath().equals("Extension.extension.url") && ed.hasFixed() && sliceName.equals(ed.getFixed().primitiveValue())) { if (ed.getPath().equals("Extension.extension.url") && ed.hasFixed() && sliceName.equals(ed.getFixed().primitiveValue())) {
@ -5139,31 +5141,31 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public boolean checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { public boolean checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) {
// specific known special validations // specific known special validations
if (element.getType().equals(BUNDLE)) { if (element.getType().equals(BUNDLE)) {
return new BundleValidator(context, debug, serverBase, this, xverManager, jurisdiction).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode); return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode);
} else if (element.getType().equals("Observation")) { } else if (element.getType().equals("Observation")) {
return validateObservation(errors, element, stack); return validateObservation(errors, element, stack);
} else if (element.getType().equals("Questionnaire")) { } else if (element.getType().equals("Questionnaire")) {
return new QuestionnaireValidator(context, debug, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager, jurisdiction).validateQuestionannaire(errors, element, element, stack); return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack);
} else if (element.getType().equals("QuestionnaireResponse")) { } else if (element.getType().equals("QuestionnaireResponse")) {
return new QuestionnaireValidator(context, debug, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager, jurisdiction).validateQuestionannaireResponse(hostContext, errors, element, stack); return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack);
} else if (element.getType().equals("Measure")) { } else if (element.getType().equals("Measure")) {
return new MeasureValidator(context, debug, timeTracker, xverManager, jurisdiction, this).validateMeasure(hostContext, errors, element, stack); return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack);
} else if (element.getType().equals("MeasureReport")) { } else if (element.getType().equals("MeasureReport")) {
return new MeasureValidator(context, debug, timeTracker, xverManager, jurisdiction, this).validateMeasureReport(hostContext, errors, element, stack); return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack);
} else if (element.getType().equals("CapabilityStatement")) { } else if (element.getType().equals("CapabilityStatement")) {
return validateCapabilityStatement(errors, element, stack); return validateCapabilityStatement(errors, element, stack);
} else if (element.getType().equals("CodeSystem")) { } else if (element.getType().equals("CodeSystem")) {
return new CodeSystemValidator(context, debug, timeTracker, this, xverManager, jurisdiction).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())); return new CodeSystemValidator(this).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang()));
} else if (element.getType().equals("ConceptMap")) { } else if (element.getType().equals("ConceptMap")) {
return new ConceptMapValidator(context, debug, timeTracker, this, xverManager, jurisdiction).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())); return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang()));
} else if (element.getType().equals("SearchParameter")) { } else if (element.getType().equals("SearchParameter")) {
return new SearchParameterValidator(context, debug, timeTracker, fpe, xverManager, jurisdiction).validateSearchParameter(errors, element, stack); return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack);
} else if (element.getType().equals("StructureDefinition")) { } else if (element.getType().equals("StructureDefinition")) {
return new StructureDefinitionValidator(context, debug, timeTracker, fpe, wantCheckSnapshotUnchanged, xverManager, jurisdiction, forPublication).validateStructureDefinition(errors, element, stack); return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack);
} else if (element.getType().equals("StructureMap")) { } else if (element.getType().equals("StructureMap")) {
return new StructureMapValidator(context, debug, timeTracker, fpe, xverManager,profileUtilities, jurisdiction).validateStructureMap(errors, element, stack); return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack);
} else if (element.getType().equals("ValueSet")) { } else if (element.getType().equals("ValueSet")) {
return new ValueSetValidator(context, debug, timeTracker, this, xverManager, jurisdiction, allowExamples).validateValueSet(errors, element, stack); return new ValueSetValidator(this).validateValueSet(errors, element, stack);
} else { } else {
return true; return true;
} }
@ -6699,9 +6701,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
codingObserver.setCheckIPSCodes(checkIPSCodes); codingObserver.setCheckIPSCodes(checkIPSCodes);
} }
public InstanceValidator setForPublication(boolean forPublication) { public InstanceValidator setForPublication(boolean forPublication) {
this.forPublication = forPublication; this.forPublication = forPublication;
if (forPublication) {
warnOnDraftOrExperimental = true;
}
return this; return this;
} }
public boolean isWarnOnDraftOrExperimental() {
return warnOnDraftOrExperimental;
}
public InstanceValidator setWarnOnDraftOrExperimental(boolean warnOnDraftOrExperimental) {
this.warnOnDraftOrExperimental = warnOnDraftOrExperimental;
return this;
}
} }

View File

@ -33,13 +33,10 @@ import org.hl7.fhir.validation.instance.utils.ValidatorHostContext;
public class BundleValidator extends BaseValidator { public class BundleValidator extends BaseValidator {
public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?"; public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?";
private String serverBase; private String serverBase;
private InstanceValidator validator;
public BundleValidator(IWorkerContext context, boolean debug, String serverBase, InstanceValidator validator, XVerExtensionManager xverManager, Coding jurisdiction) { public BundleValidator(BaseValidator parent, String serverBase) {
super(context, xverManager, debug); super(parent);
this.serverBase = serverBase; this.serverBase = serverBase;
this.validator = validator;
this.jurisdiction = jurisdiction;
} }
public boolean validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidatorHostContext hostContext, PercentageTracker pct, ValidationMode mode) { public boolean validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidatorHostContext hostContext, PercentageTracker pct, ValidationMode mode) {
@ -118,19 +115,19 @@ public class BundleValidator extends BaseValidator {
String rtype = entry.getNamedChild(RESOURCE).fhirType(); String rtype = entry.getNamedChild(RESOURCE).fhirType();
int rcount = counter.containsKey(rtype) ? counter.get(rtype)+1 : 0; int rcount = counter.containsKey(rtype) ? counter.get(rtype)+1 : 0;
counter.put(rtype, rcount); counter.put(rtype, rcount);
for (BundleValidationRule bvr : validator.getBundleValidationRules()) { for (BundleValidationRule bvr : validator().getBundleValidationRules()) {
if (meetsRule(bvr, rtype, rcount, count)) { if (meetsRule(bvr, rtype, rcount, count)) {
StructureDefinition defn = validator.getContext().fetchResource(StructureDefinition.class, bvr.getProfile()); StructureDefinition defn = context.fetchResource(StructureDefinition.class, bvr.getProfile());
if (defn == null) { if (defn == null) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_PROFILE_UNKNOWN, bvr.getRule(), bvr.getProfile())); throw new Error(context.formatMessage(I18nConstants.BUNDLE_RULE_PROFILE_UNKNOWN, bvr.getRule(), bvr.getProfile()));
} else { } else {
Element res = entry.getNamedChild(RESOURCE); Element res = entry.getNamedChild(RESOURCE);
NodeStack rstack = estack.push(res, -1, null, null); NodeStack rstack = estack.push(res, -1, null, null);
if (validator.isCrumbTrails()) { if (validator().isCrumbTrails()) {
res.addMessage(signpost(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, res.line(), res.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_BUNDLE_PARAM, defn.getUrl())); res.addMessage(signpost(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, res.line(), res.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_BUNDLE_PARAM, defn.getUrl()));
} }
stack.resetIds(); stack.resetIds();
ok = validator.startInner(hostContext, errors, res, res, defn, rstack, false, pct, mode) && ok; ok = validator().startInner(hostContext, errors, res, res, defn, rstack, false, pct, mode) && ok;
} }
} }
} }
@ -142,6 +139,10 @@ public class BundleValidator extends BaseValidator {
return ok; return ok;
} }
private InstanceValidator validator() {
return (InstanceValidator) parent;
}
private boolean validateLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, String type, List<Element> entries) { private boolean validateLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, String type, List<Element> entries) {
switch (type) { switch (type) {
case "document": return validateDocumentLink(errors, bundle, links, link, stack, entries); case "document": return validateDocumentLink(errors, bundle, links, link, stack, entries);
@ -802,22 +803,22 @@ public class BundleValidator extends BaseValidator {
public boolean meetsRule(BundleValidationRule bvr, String rtype, int rcount, int count) { public boolean meetsRule(BundleValidationRule bvr, String rtype, int rcount, int count) {
if (bvr.getRule() == null) { if (bvr.getRule() == null) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_NONE)); throw new Error(context.formatMessage(I18nConstants.BUNDLE_RULE_NONE));
} }
String rule = bvr.getRule(); String rule = bvr.getRule();
String t = rule.contains(":") ? rule.substring(0, rule.indexOf(":")) : Utilities.isInteger(rule) ? null : rule; String t = rule.contains(":") ? rule.substring(0, rule.indexOf(":")) : Utilities.isInteger(rule) ? null : rule;
String index = rule.contains(":") ? rule.substring(rule.indexOf(":")+1) : Utilities.isInteger(rule) ? rule : null; String index = rule.contains(":") ? rule.substring(rule.indexOf(":")+1) : Utilities.isInteger(rule) ? rule : null;
if (Utilities.noString(t) && Utilities.noString(index)) { if (Utilities.noString(t) && Utilities.noString(index)) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_NONE)); throw new Error(context.formatMessage(I18nConstants.BUNDLE_RULE_NONE));
} }
if (!Utilities.noString(t)) { if (!Utilities.noString(t)) {
if (!validator.getContext().getResourceNames().contains(t)) { if (!context.getResourceNames().contains(t)) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_UNKNOWN, t)); throw new Error(context.formatMessage(I18nConstants.BUNDLE_RULE_UNKNOWN, t));
} }
} }
if (!Utilities.noString(index)) { if (!Utilities.noString(index)) {
if (!Utilities.isInteger(index)) { if (!Utilities.isInteger(index)) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_INVALID_INDEX, index)); throw new Error(context.formatMessage(I18nConstants.BUNDLE_RULE_INVALID_INDEX, index));
} }
} }
if (t == null) { if (t == null) {

View File

@ -21,15 +21,8 @@ import org.hl7.fhir.validation.instance.utils.NodeStack;
public class CodeSystemValidator extends BaseValidator { public class CodeSystemValidator extends BaseValidator {
private InstanceValidator parent; public CodeSystemValidator(BaseValidator parent) {
super(parent);
public CodeSystemValidator(IWorkerContext context, boolean debug, TimeTracker timeTracker, InstanceValidator parent, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager, debug);
source = Source.InstanceValidator;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
this.parent = parent;
} }
public boolean validateCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack, ValidationOptions options) { public boolean validateCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack, ValidationOptions options) {

View File

@ -48,14 +48,8 @@ public class ConceptMapValidator extends BaseValidator {
} }
private InstanceValidator parent; public ConceptMapValidator(BaseValidator parent) {
super(parent);
public ConceptMapValidator(IWorkerContext context, boolean debug, TimeTracker timeTracker, InstanceValidator parent, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager, debug);
source = Source.InstanceValidator;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
this.parent = parent;
} }
public boolean validateConceptMap(List<ValidationMessage> errors, Element cm, NodeStack stack, ValidationOptions options) { public boolean validateConceptMap(List<ValidationMessage> errors, Element cm, NodeStack stack, ValidationOptions options) {

View File

@ -11,7 +11,6 @@ import java.util.List;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.JsonParser; import org.hl7.fhir.r5.elementmodel.JsonParser;
import org.hl7.fhir.r5.elementmodel.ObjectConverter; import org.hl7.fhir.r5.elementmodel.ObjectConverter;
@ -26,31 +25,22 @@ import org.hl7.fhir.r5.model.Measure.MeasureGroupStratifierComponent;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.renderers.DataRenderer; import org.hl7.fhir.r5.renderers.DataRenderer;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.xml.XMLUtil; import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.instance.InstanceValidator;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
import org.hl7.fhir.validation.instance.utils.ValidatorHostContext; import org.hl7.fhir.validation.instance.utils.ValidatorHostContext;
import org.w3c.dom.Document; import org.w3c.dom.Document;
public class MeasureValidator extends BaseValidator { public class MeasureValidator extends BaseValidator {
private InstanceValidator parent;
public MeasureValidator(IWorkerContext context, boolean debug, TimeTracker timeTracker, XVerExtensionManager xverManager, Coding jurisdiction, InstanceValidator parent) {
super(context, xverManager, debug);
source = Source.InstanceValidator;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
this.parent = parent;
public MeasureValidator(BaseValidator parent) {
super(parent);
} }
public boolean validateMeasure(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack) throws FHIRException { public boolean validateMeasure(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack) throws FHIRException {

View File

@ -9,7 +9,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.ObjectConverter; import org.hl7.fhir.r5.elementmodel.ObjectConverter;
@ -26,7 +25,6 @@ import org.hl7.fhir.r5.model.TimeType;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
@ -39,7 +37,6 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator; import org.hl7.fhir.validation.instance.EnableWhenEvaluator;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack; import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack;
@ -128,14 +125,11 @@ public class QuestionnaireValidator extends BaseValidator {
private FHIRPathEngine fpe; private FHIRPathEngine fpe;
private QuestionnaireMode questionnaireMode; private QuestionnaireMode questionnaireMode;
public QuestionnaireValidator(IWorkerContext context, boolean debug, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker, QuestionnaireMode questionnaireMode, XVerExtensionManager xverManager, Coding jurisdiction) { public QuestionnaireValidator(BaseValidator parent, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, QuestionnaireMode questionnaireMode) {
super(context, xverManager, debug); super(parent);
source = Source.InstanceValidator;
this.myEnableWhenEvaluator = myEnableWhenEvaluator; this.myEnableWhenEvaluator = myEnableWhenEvaluator;
this.fpe = fpe; this.fpe = fpe;
this.timeTracker = timeTracker;
this.questionnaireMode = questionnaireMode; this.questionnaireMode = questionnaireMode;
this.jurisdiction = jurisdiction;
} }
public boolean validateQuestionannaire(List<ValidationMessage> errors, Element element, Element element2, NodeStack stack) { public boolean validateQuestionannaire(List<ValidationMessage> errors, Element element, Element element2, NodeStack stack) {

View File

@ -5,22 +5,18 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ExpressionNode; import org.hl7.fhir.r5.model.ExpressionNode;
import org.hl7.fhir.r5.model.ExpressionNode.Kind; import org.hl7.fhir.r5.model.ExpressionNode.Kind;
import org.hl7.fhir.r5.model.ExpressionNode.Operation; import org.hl7.fhir.r5.model.ExpressionNode.Operation;
import org.hl7.fhir.r5.model.SearchParameter; import org.hl7.fhir.r5.model.SearchParameter;
import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
public class SearchParameterValidator extends BaseValidator { public class SearchParameterValidator extends BaseValidator {
@ -36,12 +32,9 @@ public class SearchParameterValidator extends BaseValidator {
private FHIRPathEngine fpe; private FHIRPathEngine fpe;
public SearchParameterValidator(IWorkerContext context, boolean debug, TimeTracker timeTracker, FHIRPathEngine fpe, XVerExtensionManager xverManager, Coding jurisdiction) { public SearchParameterValidator(BaseValidator parent, FHIRPathEngine fpe) {
super(context, xverManager, debug); super (parent);
source = Source.InstanceValidator;
this.fpe = fpe; this.fpe = fpe;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
} }
public boolean validateSearchParameter(List<ValidationMessage> errors, Element cs, NodeStack stack) { public boolean validateSearchParameter(List<ValidationMessage> errors, Element cs, NodeStack stack) {

View File

@ -16,7 +16,6 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.elementmodel.Manager;
@ -28,6 +27,7 @@ import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.ExpressionNode; import org.hl7.fhir.r5.model.ExpressionNode;
import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
@ -37,16 +37,13 @@ import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
public class StructureDefinitionValidator extends BaseValidator { public class StructureDefinitionValidator extends BaseValidator {
@ -63,14 +60,10 @@ public class StructureDefinitionValidator extends BaseValidator {
private FHIRPathEngine fpe; private FHIRPathEngine fpe;
private boolean wantCheckSnapshotUnchanged; private boolean wantCheckSnapshotUnchanged;
public StructureDefinitionValidator(IWorkerContext context, boolean debug, TimeTracker timeTracker, FHIRPathEngine fpe, boolean wantCheckSnapshotUnchanged, XVerExtensionManager xverManager, Coding jurisdiction, boolean forPublication) { public StructureDefinitionValidator(BaseValidator parent, FHIRPathEngine fpe, boolean wantCheckSnapshotUnchanged) {
super(context, xverManager, debug); super(parent);
source = Source.InstanceValidator;
this.fpe = fpe; this.fpe = fpe;
this.timeTracker = timeTracker;
this.wantCheckSnapshotUnchanged = wantCheckSnapshotUnchanged; this.wantCheckSnapshotUnchanged = wantCheckSnapshotUnchanged;
this.jurisdiction = jurisdiction;
this.forPublication = forPublication;
} }
public boolean validateStructureDefinition(List<ValidationMessage> errors, Element src, NodeStack stack) { public boolean validateStructureDefinition(List<ValidationMessage> errors, Element src, NodeStack stack) {
@ -831,7 +824,7 @@ public class StructureDefinitionValidator extends BaseValidator {
} else { } else {
for (Element profile : profiles) { for (Element profile : profiles) {
ok = validateTypeProfile(errors, profile, code, stack.push(profile, -1, null, null), path) && ok; ok = validateTypeProfile(errors, profile, code, stack.push(profile, -1, null, null), path, sd) && ok;
} }
profiles = type.getChildrenByName("targetProfile"); profiles = type.getChildrenByName("targetProfile");
for (Element profile : profiles) { for (Element profile : profiles) {
@ -906,7 +899,7 @@ public class StructureDefinitionValidator extends BaseValidator {
return codes; return codes;
} }
private boolean validateTypeProfile(List<ValidationMessage> errors, Element profile, String code, NodeStack stack, String path) { private boolean validateTypeProfile(List<ValidationMessage> errors, Element profile, String code, NodeStack stack, String path, StructureDefinition source) {
boolean ok = true; boolean ok = true;
String p = profile.primitiveValue(); String p = profile.primitiveValue();
StructureDefinition sd = context.fetchResource(StructureDefinition.class, p); StructureDefinition sd = context.fetchResource(StructureDefinition.class, p);
@ -921,6 +914,7 @@ public class StructureDefinitionValidator extends BaseValidator {
ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code, path) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_PROFILE_WRONG, p, t, code, path) && ok;
} else { } else {
if (t.getType().equals("Extension")) { if (t.getType().equals("Extension")) {
checkDefinitionStatus(errors, profile, path, sd, source, context.formatMessage(I18nConstants.MSG_DEPENDS_ON_EXTENSION));
boolean isModifierDefinition = checkIsModifierExtension(sd); boolean isModifierDefinition = checkIsModifierExtension(sd);
boolean isModifierContext = path.endsWith(".modifierExtension"); boolean isModifierContext = path.endsWith(".modifierExtension");
if (isModifierDefinition) { if (isModifierDefinition) {
@ -928,6 +922,8 @@ public class StructureDefinitionValidator extends BaseValidator {
} else { } else {
ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), !isModifierContext, I18nConstants.SD_ED_TYPE_PROFILE_IS_MODIFIER, p, t, code, path) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), !isModifierContext, I18nConstants.SD_ED_TYPE_PROFILE_IS_MODIFIER, p, t, code, path) && ok;
} }
} else {
checkDefinitionStatus(errors, profile, path, sd, source, context.formatMessage(I18nConstants.MSG_DEPENDS_ON_PROFILE));
} }
} }
} }

View File

@ -6,7 +6,6 @@ import java.util.List;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ConceptMap; import org.hl7.fhir.r5.model.ConceptMap;
@ -29,7 +28,6 @@ import org.hl7.fhir.r5.terminologies.ConceptMapUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetUtilities; import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup; import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup;
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities; import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
@ -38,9 +36,7 @@ import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
public class StructureMapValidator extends BaseValidator { public class StructureMapValidator extends BaseValidator {
@ -300,15 +296,11 @@ public class StructureMapValidator extends BaseValidator {
private ContextUtilities cu; private ContextUtilities cu;
private List<StructureMap> imports = new ArrayList<>(); private List<StructureMap> imports = new ArrayList<>();
public StructureMapValidator(IWorkerContext context, boolean debug, TimeTracker timeTracker, FHIRPathEngine fpe, XVerExtensionManager xverManager, ProfileUtilities profileUtilities, Coding jurisdiction) { public StructureMapValidator(BaseValidator parent, FHIRPathEngine fpe, ProfileUtilities profileUtilities) {
super(context, xverManager, debug); super(parent);
source = Source.InstanceValidator;
this.fpe = fpe; this.fpe = fpe;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
this.profileUtilities = profileUtilities; this.profileUtilities = profileUtilities;
this.cu = new ContextUtilities(context); this.cu = new ContextUtilities(context);
} }
public boolean isAbstractType(List<TypeRefComponent> list) { public boolean isAbstractType(List<TypeRefComponent> list) {

View File

@ -3,7 +3,6 @@ package org.hl7.fhir.validation.instance.type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.CodingValidationRequest; import org.hl7.fhir.r5.context.IWorkerContext.CodingValidationRequest;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
@ -11,16 +10,13 @@ import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.codesystem.CodeSystemChecker; import org.hl7.fhir.validation.codesystem.CodeSystemChecker;
import org.hl7.fhir.validation.codesystem.GeneralCodeSystemChecker; import org.hl7.fhir.validation.codesystem.GeneralCodeSystemChecker;
import org.hl7.fhir.validation.codesystem.SnomedCTChecker; import org.hl7.fhir.validation.codesystem.SnomedCTChecker;
@ -54,15 +50,8 @@ public class ValueSetValidator extends BaseValidator {
} }
private InstanceValidator parent; public ValueSetValidator(InstanceValidator parent) {
super(parent);
public ValueSetValidator(IWorkerContext context, boolean debug, TimeTracker timeTracker, InstanceValidator parent, XVerExtensionManager xverManager, Coding jurisdiction, boolean allowExamples) {
super(context, xverManager, debug);
source = Source.InstanceValidator;
this.timeTracker = timeTracker;
this.parent = parent;
this.jurisdiction = jurisdiction;
this.allowExamples = allowExamples;
} }
public boolean validateValueSet(List<ValidationMessage> errors, Element vs, NodeStack stack) { public boolean validateValueSet(List<ValidationMessage> errors, Element vs, NodeStack stack) {
@ -169,7 +158,7 @@ public class ValueSetValidator extends BaseValidator {
} }
cc++; cc++;
} }
if (parent.isValidateValueSetCodesOnTxServer() && batch.size() > 0 & !context.isNoTerminologyServer()) { if (((InstanceValidator) parent).isValidateValueSetCodesOnTxServer() && batch.size() > 0 & !context.isNoTerminologyServer()) {
long t = System.currentTimeMillis(); long t = System.currentTimeMillis();
if (parent.isDebug()) { if (parent.isDebug()) {
System.out.println(" : Validate "+batch.size()+" codes from "+system+" for "+vsid); System.out.println(" : Validate "+batch.size()+" codes from "+system+" for "+vsid);

View File

@ -65,10 +65,10 @@ public class TxTester {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new TxTester(new InternalTxLoader(args[0]), args[1], "true".equals(args[2])).execute(args[2], args[3]); new TxTester(new InternalTxLoader(args[0]), args[1], "true".equals(args[2])).execute(args[2], new ArrayList<>(), args[3]);
} }
public boolean execute(String version, String filter) throws IOException, URISyntaxException { public boolean execute(String version, List<String> modes, String filter) throws IOException, URISyntaxException {
if (output == null) { if (output == null) {
output = Utilities.path("[tmp]", serverId()); output = Utilities.path("[tmp]", serverId());
} }
@ -77,6 +77,7 @@ public class TxTester {
System.out.println(" Source for tests: "+loader.describe()); System.out.println(" Source for tests: "+loader.describe());
System.out.println(" Output Directory: "+output); System.out.println(" Output Directory: "+output);
System.out.println(" Term Service Url: "+server); System.out.println(" Term Service Url: "+server);
System.out.println(" Test Exec Modes: "+modes.toString());
if (version != null) { if (version != null) {
System.out.println(" Tx FHIR Version: "+version); System.out.println(" Tx FHIR Version: "+version);
} }
@ -91,7 +92,7 @@ public class TxTester {
ITerminologyClient tx = connectToServer(); ITerminologyClient tx = connectToServer();
boolean ok = checkClient(tx); boolean ok = checkClient(tx);
for (JsonObject suite : tests.getJsonObjects("suites")) { for (JsonObject suite : tests.getJsonObjects("suites")) {
ok = runSuite(suite, tx, filter, json.forceArray("suites")) && ok; ok = runSuite(suite, tx, modes, filter, json.forceArray("suites")) && ok;
} }
TextFile.stringToFile(JsonParser.compose(json, true), Utilities.path(output, "test-results.json")); TextFile.stringToFile(JsonParser.compose(json, true), Utilities.path(output, "test-results.json"));
if (ok) { if (ok) {
@ -137,20 +138,20 @@ public class TxTester {
} }
public String executeTest(JsonObject suite, JsonObject test) throws URISyntaxException, FHIRFormatError, FileNotFoundException, IOException { public String executeTest(JsonObject suite, JsonObject test, List<String> modes) throws URISyntaxException, FHIRFormatError, FileNotFoundException, IOException {
error = null; error = null;
if (tx == null) { if (tx == null) {
tx = connectToServer(); tx = connectToServer();
checkClient(tx); checkClient(tx);
} }
List<Resource> setup = loadSetupResources(suite); List<Resource> setup = loadSetupResources(suite);
if (runTest(test, tx, setup, "*", null)) { if (runTest(test, tx, setup, modes, "*", null)) {
return null; return null;
} else { } else {
return error; return error;
} }
} }
private boolean runSuite(JsonObject suite, ITerminologyClient tx, String filter, JsonArray output) throws FHIRFormatError, FileNotFoundException, IOException { private boolean runSuite(JsonObject suite, ITerminologyClient tx, List<String> modes, String filter, JsonArray output) throws FHIRFormatError, FileNotFoundException, IOException {
System.out.println("Group "+suite.asString("name")); System.out.println("Group "+suite.asString("name"));
JsonObject outputS = new JsonObject(); JsonObject outputS = new JsonObject();
if (output != null) { if (output != null) {
@ -160,12 +161,12 @@ public class TxTester {
List<Resource> setup = loadSetupResources(suite); List<Resource> setup = loadSetupResources(suite);
boolean ok = true; boolean ok = true;
for (JsonObject test : suite.getJsonObjects("tests")) { for (JsonObject test : suite.getJsonObjects("tests")) {
ok = runTest(test, tx, setup, filter, outputS.forceArray("tests")) && ok; ok = runTest(test, tx, setup, modes, filter, outputS.forceArray("tests")) && ok;
} }
return ok; return ok;
} }
private boolean runTest(JsonObject test, ITerminologyClient tx, List<Resource> setup, String filter, JsonArray output) throws FHIRFormatError, DefinitionException, FileNotFoundException, FHIRException, IOException { private boolean runTest(JsonObject test, ITerminologyClient tx, List<Resource> setup, List<String> modes, String filter, JsonArray output) throws FHIRFormatError, DefinitionException, FileNotFoundException, FHIRException, IOException {
JsonObject outputT = new JsonObject(); JsonObject outputT = new JsonObject();
if (output != null) { if (output != null) {
output.add(outputT); output.add(outputT);
@ -175,9 +176,9 @@ public class TxTester {
if (Utilities.noString(filter) || filter.equals("*") || test.asString("name").contains(filter)) { if (Utilities.noString(filter) || filter.equals("*") || test.asString("name").contains(filter)) {
System.out.print(" Test "+test.asString("name")+": "); System.out.print(" Test "+test.asString("name")+": ");
try { try {
Parameters req = (Parameters) loader.loadResource(test.asString("request")); Parameters req = (Parameters) loader.loadResource(chooseParam(test, "request", modes));
String fn = test.asString("response"); String fn = chooseParam(test, "response", modes);
String resp = TextFile.bytesToString(loader.loadContent(fn)); String resp = TextFile.bytesToString(loader.loadContent(fn));
String fp = Utilities.path("[tmp]", serverId(), fn); String fp = Utilities.path("[tmp]", serverId(), fn);
File fo = new File(fp); File fo = new File(fp);
@ -217,6 +218,15 @@ public class TxTester {
} }
} }
private String chooseParam(JsonObject test, String name, List<String> modes) {
for (String mode : modes) {
if (test.has(name+":"+mode)) {
return test.asString(name+":"+mode);
}
}
return test.asString(name);
}
private Parameters loadProfile(JsonObject test) throws FHIRFormatError, DefinitionException, FileNotFoundException, FHIRException, IOException { private Parameters loadProfile(JsonObject test) throws FHIRFormatError, DefinitionException, FileNotFoundException, FHIRException, IOException {
if (test.has("profile")) { if (test.has("profile")) {
return (Parameters) loader.loadResource(test.asString("profile")); return (Parameters) loader.loadResource(test.asString("profile"));

View File

@ -53,7 +53,7 @@ public class TxTesterScrubbers {
} }
@Override @Override
public void visit(Resource resource) { public void visit(Object context, Resource resource) {
if (resource instanceof DomainResource) { if (resource instanceof DomainResource) {
DomainResource dr = (DomainResource) resource; DomainResource dr = (DomainResource) resource;
dr.getExtension().removeIf(ext -> !isManagedExtension(ext)); dr.getExtension().removeIf(ext -> !isManagedExtension(ext));
@ -61,7 +61,7 @@ public class TxTesterScrubbers {
} }
@Override @Override
public void visit(Element element) { public void visit(Object context, Element element) {
element.getExtension().removeIf(ext -> !isManagedExtension(ext)); element.getExtension().removeIf(ext -> !isManagedExtension(ext));
} }
} }
@ -69,7 +69,7 @@ public class TxTesterScrubbers {
public static void scrubDR(DomainResource dr, boolean tight) { public static void scrubDR(DomainResource dr, boolean tight) {
dr.setText(null); dr.setText(null);
dr.setMeta(null); dr.setMeta(null);
new ElementVisitor(new TxTesterScrubberVisitor(tight)).visit(dr); new ElementVisitor(new TxTesterScrubberVisitor(tight)).visit(null, dr);
} }
public static void scrubVS(ValueSet vs, boolean tight) { public static void scrubVS(ValueSet vs, boolean tight) {

View File

@ -124,7 +124,11 @@ public class TxTesterSorters {
public int compare(ValueSetExpansionParameterComponent o1, ValueSetExpansionParameterComponent o2) { public int compare(ValueSetExpansionParameterComponent o1, ValueSetExpansionParameterComponent o2) {
Collections.sort(o1.getExtension(), new ExtensionSorter()); Collections.sort(o1.getExtension(), new ExtensionSorter());
Collections.sort(o2.getExtension(), new ExtensionSorter()); Collections.sort(o2.getExtension(), new ExtensionSorter());
return o1.getName().compareTo(o2.getName()); int res = o1.getName().compareTo(o2.getName());
if (res == 0) {
res = o1.getValue().primitiveValue().compareTo(o2.getValue().primitiveValue());
}
return res;
} }
} }

View File

@ -81,6 +81,7 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader {
private JsonObjectPair setup; private JsonObjectPair setup;
private String version = "5.0.0"; private String version = "5.0.0";
private static TxTester tester; private static TxTester tester;
private List<String> modes = new ArrayList<>();
public ExternalTerminologyServiceTests(String name, JsonObjectPair setup) { public ExternalTerminologyServiceTests(String name, JsonObjectPair setup) {
this.setup = setup; this.setup = setup;
@ -93,7 +94,7 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader {
if (tester == null) { if (tester == null) {
tester = new TxTester(this, SERVER, true); tester = new TxTester(this, SERVER, true);
} }
String err = tester.executeTest(setup.suite, setup.test); String err = tester.executeTest(setup.suite, setup.test, modes);
Assertions.assertTrue(err == null, err); Assertions.assertTrue(err == null, err);
} else { } else {
Assertions.assertTrue(true); Assertions.assertTrue(true);

View File

@ -117,7 +117,6 @@ public class TerminologyServiceTests {
public void test() throws Exception { public void test() throws Exception {
if (baseEngine == null) { if (baseEngine == null) {
baseEngine = TestUtilities.getValidationEngineNoTxServer("hl7.fhir.r5.core#5.0.0", FhirPublication.R5, "5.0.0"); baseEngine = TestUtilities.getValidationEngineNoTxServer("hl7.fhir.r5.core#5.0.0", FhirPublication.R5, "5.0.0");
} }
ValidationEngine engine = new ValidationEngine(this.baseEngine); ValidationEngine engine = new ValidationEngine(this.baseEngine);
for (String s : setup.suite.forceArray("setup").asStrings()) { for (String s : setup.suite.forceArray("setup").asStrings()) {

View File

@ -143,3 +143,18 @@ v: {
"system" : "http://unstats.un.org/unsd/methods/m49/m49.htm" "system" : "http://unstats.un.org/unsd/methods/m49/m49.htm"
} }
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------
{"code" : {
"code" : "json"
}, "url": "http://hl7.org/fhir/ValueSet/mimetypes", "version": "5.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"true", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "json",
"code" : "json",
"system" : "urn:ietf:bcp:13"
}
-------------------------------------------------------------------------------------