Merge branch 'hapifhir:master' into bug/missing-audit-events
This commit is contained in:
commit
0d3807e7fd
|
@ -3,35 +3,30 @@ root = true
|
||||||
[*]
|
[*]
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
tab_width = 3
|
indent_style = space
|
||||||
indent_size = 3
|
tab_width = 4
|
||||||
|
indent_size = 4
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
|
|
||||||
[*.xml]
|
[*.xml]
|
||||||
charset = utf-8
|
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
tab_width = 3
|
tab_width = 3
|
||||||
indent_size = 3
|
indent_size = 3
|
||||||
|
|
||||||
[*.json]
|
[*.json]
|
||||||
charset = utf-8
|
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
tab_width = 3
|
tab_width = 3
|
||||||
indent_size = 3
|
indent_size = 3
|
||||||
|
|
||||||
[*.vm]
|
[*.vm]
|
||||||
charset = utf-8
|
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
tab_width = 3
|
tab_width = 3
|
||||||
indent_size = 3
|
indent_size = 3
|
||||||
|
|
||||||
|
|
||||||
[*.java]
|
[*.java]
|
||||||
charset = utf-8
|
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
tab_width = 3
|
ij_continuation_indent_size = 4
|
||||||
indent_size = 3
|
|
||||||
continuation_indent_size=3
|
|
||||||
ij_java_align_consecutive_assignments = false
|
ij_java_align_consecutive_assignments = false
|
||||||
ij_java_align_consecutive_variable_declarations = false
|
ij_java_align_consecutive_variable_declarations = false
|
||||||
ij_java_align_group_field_declarations = false
|
ij_java_align_group_field_declarations = false
|
||||||
|
|
|
@ -13,7 +13,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
# We must fetch at least the immediate parents so that if this is
|
# We must fetch at least the immediate parents so that if this is
|
||||||
# a pull request then we can checkout the head.
|
# a pull request then we can checkout the head.
|
||||||
|
@ -32,7 +32,7 @@ jobs:
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
# Override language selection by uncommenting this and choosing your languages
|
# Override language selection by uncommenting this and choosing your languages
|
||||||
# with:
|
# with:
|
||||||
# languages: go, javascript, csharp, python, cpp, java
|
# languages: go, javascript, csharp, python, cpp, java
|
||||||
|
@ -40,7 +40,7 @@ jobs:
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
|
@ -54,4 +54,4 @@ jobs:
|
||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -1001,9 +1001,9 @@ public class FhirContext {
|
||||||
*/
|
*/
|
||||||
public void registerCustomType(final Class<? extends IBase> theType) {
|
public void registerCustomType(final Class<? extends IBase> theType) {
|
||||||
Validate.notNull(theType, "theType must not be null");
|
Validate.notNull(theType, "theType must not be null");
|
||||||
|
|
||||||
ensureCustomTypeList();
|
ensureCustomTypeList();
|
||||||
myCustomTypes.add(theType);
|
myCustomTypes.add(theType);
|
||||||
|
myResourceNames = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1025,6 +1025,7 @@ public class FhirContext {
|
||||||
ensureCustomTypeList();
|
ensureCustomTypeList();
|
||||||
|
|
||||||
myCustomTypes.addAll(theTypes);
|
myCustomTypes.addAll(theTypes);
|
||||||
|
myResourceNames = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseRuntimeElementDefinition<?> scanDatatype(final Class<? extends IElement> theResourceType) {
|
private BaseRuntimeElementDefinition<?> scanDatatype(final Class<? extends IElement> theResourceType) {
|
||||||
|
@ -1177,7 +1178,14 @@ public class FhirContext {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!myInitialized && !myInitializing) {
|
if (!myInitialized && !myInitializing) {
|
||||||
myInitializing = true;
|
myInitializing = true;
|
||||||
|
try {
|
||||||
scanResourceTypes(toElementList(myResourceTypesToScan));
|
scanResourceTypes(toElementList(myResourceTypesToScan));
|
||||||
|
} catch (Exception e) {
|
||||||
|
ourLog.error("Failed to initialize FhirContext", e);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
myInitializing = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -553,11 +553,29 @@ public interface IValidationSupport {
|
||||||
private String myCodeSystemVersion;
|
private String myCodeSystemVersion;
|
||||||
private List<BaseConceptProperty> myProperties;
|
private List<BaseConceptProperty> myProperties;
|
||||||
private String myDisplay;
|
private String myDisplay;
|
||||||
|
private String mySourceDetails;
|
||||||
|
|
||||||
public CodeValidationResult() {
|
public CodeValidationResult() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This field may contain information about what the source of the
|
||||||
|
* validation information was.
|
||||||
|
*/
|
||||||
|
public String getSourceDetails() {
|
||||||
|
return mySourceDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This field may contain information about what the source of the
|
||||||
|
* validation information was.
|
||||||
|
*/
|
||||||
|
public CodeValidationResult setSourceDetails(String theSourceDetails) {
|
||||||
|
mySourceDetails = theSourceDetails;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDisplay() {
|
public String getDisplay() {
|
||||||
return myDisplay;
|
return myDisplay;
|
||||||
}
|
}
|
||||||
|
@ -691,8 +709,9 @@ public interface IValidationSupport {
|
||||||
private boolean myFound;
|
private boolean myFound;
|
||||||
private String mySearchedForCode;
|
private String mySearchedForCode;
|
||||||
private String mySearchedForSystem;
|
private String mySearchedForSystem;
|
||||||
private List<IValidationSupport.BaseConceptProperty> myProperties;
|
private List<BaseConceptProperty> myProperties;
|
||||||
private List<ConceptDesignation> myDesignations;
|
private List<ConceptDesignation> myDesignations;
|
||||||
|
private String myErrorMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -708,7 +727,7 @@ public interface IValidationSupport {
|
||||||
return myProperties;
|
return myProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProperties(List<IValidationSupport.BaseConceptProperty> theProperties) {
|
public void setProperties(List<BaseConceptProperty> theProperties) {
|
||||||
myProperties = theProperties;
|
myProperties = theProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +827,7 @@ public interface IValidationSupport {
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IValidationSupport.BaseConceptProperty next : myProperties) {
|
for (BaseConceptProperty next : myProperties) {
|
||||||
|
|
||||||
if (!properties.isEmpty()) {
|
if (!properties.isEmpty()) {
|
||||||
if (!properties.contains(next.getPropertyName())) {
|
if (!properties.contains(next.getPropertyName())) {
|
||||||
|
@ -819,11 +838,11 @@ public interface IValidationSupport {
|
||||||
IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "property");
|
IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "property");
|
||||||
ParametersUtil.addPartCode(theContext, property, "code", next.getPropertyName());
|
ParametersUtil.addPartCode(theContext, property, "code", next.getPropertyName());
|
||||||
|
|
||||||
if (next instanceof IValidationSupport.StringConceptProperty) {
|
if (next instanceof StringConceptProperty) {
|
||||||
IValidationSupport.StringConceptProperty prop = (IValidationSupport.StringConceptProperty) next;
|
StringConceptProperty prop = (StringConceptProperty) next;
|
||||||
ParametersUtil.addPartString(theContext, property, "value", prop.getValue());
|
ParametersUtil.addPartString(theContext, property, "value", prop.getValue());
|
||||||
} else if (next instanceof IValidationSupport.CodingConceptProperty) {
|
} else if (next instanceof CodingConceptProperty) {
|
||||||
IValidationSupport.CodingConceptProperty prop = (IValidationSupport.CodingConceptProperty) next;
|
CodingConceptProperty prop = (CodingConceptProperty) next;
|
||||||
ParametersUtil.addPartCoding(
|
ParametersUtil.addPartCoding(
|
||||||
theContext, property, "value", prop.getCodeSystem(), prop.getCode(), prop.getDisplay());
|
theContext, property, "value", prop.getCodeSystem(), prop.getCode(), prop.getDisplay());
|
||||||
} else {
|
} else {
|
||||||
|
@ -846,6 +865,14 @@ public interface IValidationSupport {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setErrorMessage(String theErrorMessage) {
|
||||||
|
myErrorMessage = theErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMessage() {
|
||||||
|
return myErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
public static LookupCodeResult notFound(String theSearchedForSystem, String theSearchedForCode) {
|
public static LookupCodeResult notFound(String theSearchedForSystem, String theSearchedForCode) {
|
||||||
return new LookupCodeResult()
|
return new LookupCodeResult()
|
||||||
.setFound(false)
|
.setFound(false)
|
||||||
|
|
|
@ -1484,6 +1484,15 @@ public enum Pointcut implements IPointcut {
|
||||||
* to the new contents of the resource. These changes will be reflected in
|
* to the new contents of the resource. These changes will be reflected in
|
||||||
* permanent storage.
|
* permanent storage.
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <b>NO-OPS:</b> If the client has submitted an update that does not actually make any changes
|
||||||
|
* (i.e. the resource they include in the PUT body is identical to the content that
|
||||||
|
* was already stored) the server may choose to ignore the update and perform
|
||||||
|
* a "NO-OP". In this case, this pointcut is still invoked, but {@link #STORAGE_PRECOMMIT_RESOURCE_UPDATED}
|
||||||
|
* will not be. Hook methods for this pointcut may make changes to the new contents of the
|
||||||
|
* resource being updated, and in this case the NO-OP will be cancelled and
|
||||||
|
* {@link #STORAGE_PRECOMMIT_RESOURCE_UPDATED} will also be invoked.
|
||||||
|
* </p>
|
||||||
* Hooks may accept the following parameters:
|
* Hooks may accept the following parameters:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource - The previous contents of the resource being updated</li>
|
* <li>org.hl7.fhir.instance.model.api.IBaseResource - The previous contents of the resource being updated</li>
|
||||||
|
@ -1617,6 +1626,10 @@ public enum Pointcut implements IPointcut {
|
||||||
* changes as storage has already occurred. Changes will not be reflected
|
* changes as storage has already occurred. Changes will not be reflected
|
||||||
* in storage, but may be reflected in the HTTP response.
|
* in storage, but may be reflected in the HTTP response.
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* NO-OP note: See {@link #STORAGE_PRESTORAGE_RESOURCE_UPDATED} for a note on
|
||||||
|
* no-op updates when no changes are detected.
|
||||||
|
* </p>
|
||||||
* Hooks may accept the following parameters:
|
* Hooks may accept the following parameters:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource - The previous contents of the resource</li>
|
* <li>org.hl7.fhir.instance.model.api.IBaseResource - The previous contents of the resource</li>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
|
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
|
||||||
import ca.uhn.fhir.model.api.ICompositeDatatype;
|
import ca.uhn.fhir.model.api.ICompositeDatatype;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
import ca.uhn.fhir.model.primitive.BooleanDt;
|
||||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
@ -58,6 +59,10 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
|
||||||
*/
|
*/
|
||||||
public abstract UriDt getSystemElement();
|
public abstract UriDt getSystemElement();
|
||||||
|
|
||||||
|
public abstract StringDt getVersionElement();
|
||||||
|
|
||||||
|
public abstract BooleanDt getUserSelectedElement();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value(s) for <b>display</b> (Representation defined by the system).
|
* Gets the value(s) for <b>display</b> (Representation defined by the system).
|
||||||
* creating it if it does
|
* creating it if it does
|
||||||
|
@ -72,13 +77,6 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
|
||||||
|
|
||||||
public abstract BaseCodingDt setDisplay(String theString);
|
public abstract BaseCodingDt setDisplay(String theString);
|
||||||
|
|
||||||
/*
|
|
||||||
todo: handle version
|
|
||||||
public abstract StringDt getVersion();
|
|
||||||
|
|
||||||
public abstract BaseCodingDt setVersion ( String theString);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
@ -181,7 +179,7 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
|
||||||
* @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
|
* @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
|
||||||
* need this functionality
|
* need this functionality
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated(since = "6.0.0")
|
||||||
@Override
|
@Override
|
||||||
public Boolean getMissing() {
|
public Boolean getMissing() {
|
||||||
return null;
|
return null;
|
||||||
|
@ -193,7 +191,7 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
|
||||||
* @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
|
* @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
|
||||||
* need this functionality
|
* need this functionality
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated(since = "6.0.0")
|
||||||
@Override
|
@Override
|
||||||
public IQueryParameterType setMissing(Boolean theMissing) {
|
public IQueryParameterType setMissing(Boolean theMissing) {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
|
|
|
@ -1033,7 +1033,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
||||||
writeOptionalTagWithTextNode(theEventWriter, "system", tag.getScheme());
|
writeOptionalTagWithTextNode(theEventWriter, "system", tag.getScheme());
|
||||||
writeOptionalTagWithTextNode(theEventWriter, "code", tag.getTerm());
|
writeOptionalTagWithTextNode(theEventWriter, "code", tag.getTerm());
|
||||||
writeOptionalTagWithTextNode(theEventWriter, "display", tag.getLabel());
|
writeOptionalTagWithTextNode(theEventWriter, "display", tag.getLabel());
|
||||||
// wipmb should we be writing the new properties here? There must be another path.
|
writeOptionalTagWithTextNode(theEventWriter, "version", tag.getVersion());
|
||||||
|
write(theEventWriter, "userSelected", tag.getUserSelectedBoolean());
|
||||||
theEventWriter.endObject();
|
theEventWriter.endObject();
|
||||||
}
|
}
|
||||||
theEventWriter.endArray();
|
theEventWriter.endArray();
|
||||||
|
|
|
@ -636,7 +636,7 @@ class ParserState<T> {
|
||||||
|
|
||||||
BaseRuntimeElementDefinition<?> target = child.getChildByName(theChildName);
|
BaseRuntimeElementDefinition<?> target = child.getChildByName(theChildName);
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
// This is a bug with the structures and shouldn't happen..
|
// This is a bug with the structures and shouldn't happen.
|
||||||
throw new DataFormatException(
|
throw new DataFormatException(
|
||||||
Msg.code(1809) + "Found unexpected element '" + theChildName + "' in parent element '"
|
Msg.code(1809) + "Found unexpected element '" + theChildName + "' in parent element '"
|
||||||
+ myDefinition.getName() + "'. Valid names are: " + child.getValidChildNames());
|
+ myDefinition.getName() + "'. Valid names are: " + child.getValidChildNames());
|
||||||
|
@ -1584,16 +1584,20 @@ class ParserState<T> {
|
||||||
|
|
||||||
private class TagState extends BaseState {
|
private class TagState extends BaseState {
|
||||||
|
|
||||||
private static final int LABEL = 2;
|
|
||||||
private static final int NONE = 0;
|
private static final int NONE = 0;
|
||||||
|
private static final int TERM = 1;
|
||||||
|
private static final int LABEL = 2;
|
||||||
|
|
||||||
private static final int SCHEME = 3;
|
private static final int SCHEME = 3;
|
||||||
private static final int TERM = 1;
|
private static final int VERSION = 4;
|
||||||
|
private static final int USER_SELECTED = 5;
|
||||||
private String myLabel;
|
private String myLabel;
|
||||||
private String myScheme;
|
private String myScheme;
|
||||||
private int mySubState = 0;
|
private int mySubState = 0;
|
||||||
private TagList myTagList;
|
private TagList myTagList;
|
||||||
private String myTerm;
|
private String myTerm;
|
||||||
|
private String myVersion;
|
||||||
|
private Boolean myUserSelected;
|
||||||
|
|
||||||
public TagState(TagList theTagList) {
|
public TagState(TagList theTagList) {
|
||||||
super(null);
|
super(null);
|
||||||
|
@ -1614,6 +1618,12 @@ class ParserState<T> {
|
||||||
case SCHEME:
|
case SCHEME:
|
||||||
myScheme = (value);
|
myScheme = (value);
|
||||||
break;
|
break;
|
||||||
|
case VERSION:
|
||||||
|
myVersion = (value);
|
||||||
|
break;
|
||||||
|
case USER_SELECTED:
|
||||||
|
myUserSelected = Boolean.valueOf(value);
|
||||||
|
break;
|
||||||
case NONE:
|
case NONE:
|
||||||
// This handles JSON encoding, which is a bit weird
|
// This handles JSON encoding, which is a bit weird
|
||||||
enteringNewElement(null, theName);
|
enteringNewElement(null, theName);
|
||||||
|
@ -1629,7 +1639,9 @@ class ParserState<T> {
|
||||||
mySubState = NONE;
|
mySubState = NONE;
|
||||||
} else {
|
} else {
|
||||||
if (isNotEmpty(myScheme) || isNotBlank(myTerm) || isNotBlank(myLabel)) {
|
if (isNotEmpty(myScheme) || isNotBlank(myTerm) || isNotBlank(myLabel)) {
|
||||||
myTagList.addTag(myScheme, myTerm, myLabel);
|
Tag tag = myTagList.addTag(myScheme, myTerm, myLabel);
|
||||||
|
tag.setUserSelectedBoolean(myUserSelected);
|
||||||
|
tag.setVersion(myVersion);
|
||||||
}
|
}
|
||||||
pop();
|
pop();
|
||||||
}
|
}
|
||||||
|
@ -1646,6 +1658,10 @@ class ParserState<T> {
|
||||||
mySubState = SCHEME;
|
mySubState = SCHEME;
|
||||||
} else if (Tag.ATTR_LABEL.equals(theLocalPart) || "display".equals(theLocalPart)) {
|
} else if (Tag.ATTR_LABEL.equals(theLocalPart) || "display".equals(theLocalPart)) {
|
||||||
mySubState = LABEL;
|
mySubState = LABEL;
|
||||||
|
} else if ("userSelected".equals(theLocalPart)) {
|
||||||
|
mySubState = USER_SELECTED;
|
||||||
|
} else if ("version".equals(theLocalPart)) {
|
||||||
|
mySubState = VERSION;
|
||||||
} else {
|
} else {
|
||||||
throw new DataFormatException(Msg.code(1818) + "Unexpected element: " + theLocalPart);
|
throw new DataFormatException(Msg.code(1818) + "Unexpected element: " + theLocalPart);
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,8 @@ public class XmlParser extends BaseParser {
|
||||||
|
|
||||||
String namespaceURI = elem.getName().getNamespaceURI();
|
String namespaceURI = elem.getName().getNamespaceURI();
|
||||||
|
|
||||||
if ("extension".equals(elem.getName().getLocalPart())) {
|
String localPart = elem.getName().getLocalPart();
|
||||||
|
if ("extension".equals(localPart)) {
|
||||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||||
String url;
|
String url;
|
||||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||||
|
@ -199,7 +200,7 @@ public class XmlParser extends BaseParser {
|
||||||
url = urlAttr.getValue();
|
url = urlAttr.getValue();
|
||||||
}
|
}
|
||||||
parserState.enteringNewElementExtension(elem, url, false, getServerBaseUrl());
|
parserState.enteringNewElementExtension(elem, url, false, getServerBaseUrl());
|
||||||
} else if ("modifierExtension".equals(elem.getName().getLocalPart())) {
|
} else if ("modifierExtension".equals(localPart)) {
|
||||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||||
String url;
|
String url;
|
||||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||||
|
@ -213,8 +214,7 @@ public class XmlParser extends BaseParser {
|
||||||
}
|
}
|
||||||
parserState.enteringNewElementExtension(elem, url, true, getServerBaseUrl());
|
parserState.enteringNewElementExtension(elem, url, true, getServerBaseUrl());
|
||||||
} else {
|
} else {
|
||||||
String elementName = elem.getName().getLocalPart();
|
parserState.enteringNewElement(namespaceURI, localPart);
|
||||||
parserState.enteringNewElement(namespaceURI, elementName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!heldComments.isEmpty()) {
|
if (!heldComments.isEmpty()) {
|
||||||
|
@ -768,6 +768,11 @@ public class XmlParser extends BaseParser {
|
||||||
writeOptionalTagWithValue(theEventWriter, "system", tag.getScheme());
|
writeOptionalTagWithValue(theEventWriter, "system", tag.getScheme());
|
||||||
writeOptionalTagWithValue(theEventWriter, "code", tag.getTerm());
|
writeOptionalTagWithValue(theEventWriter, "code", tag.getTerm());
|
||||||
writeOptionalTagWithValue(theEventWriter, "display", tag.getLabel());
|
writeOptionalTagWithValue(theEventWriter, "display", tag.getLabel());
|
||||||
|
writeOptionalTagWithValue(theEventWriter, "version", tag.getVersion());
|
||||||
|
Boolean userSelected = tag.getUserSelectedBoolean();
|
||||||
|
if (userSelected != null) {
|
||||||
|
writeOptionalTagWithValue(theEventWriter, "userSelected", userSelected.toString());
|
||||||
|
}
|
||||||
theEventWriter.writeEndElement();
|
theEventWriter.writeEndElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import ca.uhn.fhir.parser.json.BaseJsonLikeWriter;
|
||||||
import ca.uhn.fhir.parser.json.JsonLikeStructure;
|
import ca.uhn.fhir.parser.json.JsonLikeStructure;
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.StreamReadConstraints;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
@ -388,6 +389,15 @@ public class JacksonStructure implements JsonLikeStructure {
|
||||||
retVal = retVal.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
retVal = retVal.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
||||||
retVal = retVal.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
|
retVal = retVal.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
|
||||||
retVal = retVal.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
|
retVal = retVal.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
|
||||||
|
|
||||||
|
retVal.getFactory().setStreamReadConstraints(createStreamReadConstraints());
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static StreamReadConstraints createStreamReadConstraints() {
|
||||||
|
return StreamReadConstraints.builder()
|
||||||
|
.maxStringLength(Integer.MAX_VALUE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,11 @@ public class Constants {
|
||||||
public static final String PARAM_HAS = "_has";
|
public static final String PARAM_HAS = "_has";
|
||||||
public static final String PARAM_HISTORY = "_history";
|
public static final String PARAM_HISTORY = "_history";
|
||||||
public static final String PARAM_INCLUDE = "_include";
|
public static final String PARAM_INCLUDE = "_include";
|
||||||
|
/**
|
||||||
|
* @since 7.0.0
|
||||||
|
*/
|
||||||
|
public static final String PARAM_LANGUAGE = "_language";
|
||||||
|
|
||||||
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse";
|
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse";
|
||||||
public static final String PARAM_INCLUDE_RECURSE = "_include" + PARAM_INCLUDE_QUALIFIER_RECURSE;
|
public static final String PARAM_INCLUDE_RECURSE = "_include" + PARAM_INCLUDE_QUALIFIER_RECURSE;
|
||||||
public static final String PARAM_INCLUDE_QUALIFIER_ITERATE = ":iterate";
|
public static final String PARAM_INCLUDE_QUALIFIER_ITERATE = ":iterate";
|
||||||
|
@ -326,6 +331,9 @@ public class Constants {
|
||||||
*/
|
*/
|
||||||
public static final int UUID_LENGTH = 36;
|
public static final int UUID_LENGTH = 36;
|
||||||
|
|
||||||
|
public static final String BULK_DATA_ACCESS_IG_URL =
|
||||||
|
"http://hl7.org/fhir/uv/bulkdata/CapabilityStatement/bulk-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application configuration key used to enable or disable Hibernate Envers.
|
* Application configuration key used to enable or disable Hibernate Envers.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class MethodOutcome {
|
||||||
private IBaseResource myResource;
|
private IBaseResource myResource;
|
||||||
private Map<String, List<String>> myResponseHeaders;
|
private Map<String, List<String>> myResponseHeaders;
|
||||||
private Collection<Runnable> myResourceViewCallbacks;
|
private Collection<Runnable> myResourceViewCallbacks;
|
||||||
private int myResponseStatusCode;
|
private Integer myResponseStatusCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -258,6 +258,10 @@ public class MethodOutcome {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getResponseStatusCode() {
|
public int getResponseStatusCode() {
|
||||||
return myResponseStatusCode;
|
return isResponseStatusCodeSet() ? myResponseStatusCode : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResponseStatusCodeSet() {
|
||||||
|
return myResponseStatusCode != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,13 +151,27 @@ public class InternalCodingDt extends BaseCodingDt implements ICompositeDatatype
|
||||||
* is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged
|
* is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public StringDt getVersion() {
|
@Override
|
||||||
|
public StringDt getVersionElement() {
|
||||||
if (myVersion == null) {
|
if (myVersion == null) {
|
||||||
myVersion = new StringDt();
|
myVersion = new StringDt();
|
||||||
}
|
}
|
||||||
return myVersion;
|
return myVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanDt getUserSelectedElement() {
|
||||||
|
return new BooleanDt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy name for {@link #getVersionElement()}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "7.0.0")
|
||||||
|
public StringDt getVersion() {
|
||||||
|
return getVersionElement();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value(s) for <b>version</b> (Version of the system - if relevant)
|
* Sets the value(s) for <b>version</b> (Version of the system - if relevant)
|
||||||
*
|
*
|
||||||
|
|
|
@ -48,7 +48,16 @@ public enum UriParamQualifierEnum {
|
||||||
* Value <code>:below</code>
|
* Value <code>:below</code>
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
BELOW(":below");
|
BELOW(":below"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The contains modifier allows clients to indicate that a supplied URI input should be matched
|
||||||
|
* as a case-insensitive and combining-character insensitive match anywhere in the target URI.
|
||||||
|
* <p>
|
||||||
|
* Value <code>:contains</code>
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
CONTAINS(":contains");
|
||||||
|
|
||||||
private static final Map<String, UriParamQualifierEnum> KEY_TO_VALUE;
|
private static final Map<String, UriParamQualifierEnum> KEY_TO_VALUE;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ public final class HapiSystemProperties {
|
||||||
static final String TEST_MODE = "test";
|
static final String TEST_MODE = "test";
|
||||||
static final String UNIT_TEST_MODE = "unit_test_mode";
|
static final String UNIT_TEST_MODE = "unit_test_mode";
|
||||||
static final long DEFAULT_TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS = 10 * DateUtils.MILLIS_PER_SECOND;
|
static final long DEFAULT_TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS = 10 * DateUtils.MILLIS_PER_SECOND;
|
||||||
|
static final String PREVENT_INVALIDATING_CONDITIONAL_MATCH_CRITERIA =
|
||||||
|
"hapi.storage.prevent_invalidating_conditional_match_criteria";
|
||||||
|
|
||||||
private HapiSystemProperties() {}
|
private HapiSystemProperties() {}
|
||||||
|
|
||||||
|
@ -158,4 +160,9 @@ public final class HapiSystemProperties {
|
||||||
public static boolean isSuppressHapiFhirVersionLogEnabled() {
|
public static boolean isSuppressHapiFhirVersionLogEnabled() {
|
||||||
return Boolean.parseBoolean(System.getProperty(SUPPRESS_HAPI_FHIR_VERSION_LOG));
|
return Boolean.parseBoolean(System.getProperty(SUPPRESS_HAPI_FHIR_VERSION_LOG));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPreventInvalidatingConditionalMatchCriteria() {
|
||||||
|
return Boolean.parseBoolean(System.getProperty(
|
||||||
|
HapiSystemProperties.PREVENT_INVALIDATING_CONDITIONAL_MATCH_CRITERIA, Boolean.FALSE.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,9 +287,33 @@ public class FhirTerser {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts all outbound references from a resource
|
||||||
|
*
|
||||||
|
* @param theResource the resource to be analyzed
|
||||||
|
* @return a list of references to other resources
|
||||||
|
*/
|
||||||
public List<ResourceReferenceInfo> getAllResourceReferences(final IBaseResource theResource) {
|
public List<ResourceReferenceInfo> getAllResourceReferences(final IBaseResource theResource) {
|
||||||
|
return getAllResourceReferencesExcluding(theResource, Lists.newArrayList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts all outbound references from a resource, excluding any that are located on black-listed parts of the
|
||||||
|
* resource
|
||||||
|
*
|
||||||
|
* @param theResource the resource to be analyzed
|
||||||
|
* @param thePathsToExclude a list of dot-delimited paths not to include in the result
|
||||||
|
* @return a list of references to other resources
|
||||||
|
*/
|
||||||
|
public List<ResourceReferenceInfo> getAllResourceReferencesExcluding(
|
||||||
|
final IBaseResource theResource, List<String> thePathsToExclude) {
|
||||||
final ArrayList<ResourceReferenceInfo> retVal = new ArrayList<>();
|
final ArrayList<ResourceReferenceInfo> retVal = new ArrayList<>();
|
||||||
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
|
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
|
||||||
|
List<List<String>> tokenizedPathsToExclude = thePathsToExclude.stream()
|
||||||
|
.map(path -> StringUtils.split(path, "."))
|
||||||
|
.map(Lists::newArrayList)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
visit(newMap(), theResource, theResource, null, null, def, new IModelVisitor() {
|
visit(newMap(), theResource, theResource, null, null, def, new IModelVisitor() {
|
||||||
@Override
|
@Override
|
||||||
public void acceptElement(
|
public void acceptElement(
|
||||||
|
@ -301,6 +325,10 @@ public class FhirTerser {
|
||||||
if (theElement == null || theElement.isEmpty()) {
|
if (theElement == null || theElement.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thePathToElement != null && pathShouldBeExcluded(tokenizedPathsToExclude, thePathToElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (IBaseReference.class.isAssignableFrom(theElement.getClass())) {
|
if (IBaseReference.class.isAssignableFrom(theElement.getClass())) {
|
||||||
retVal.add(new ResourceReferenceInfo(
|
retVal.add(new ResourceReferenceInfo(
|
||||||
myContext, theOuterResource, thePathToElement, (IBaseReference) theElement));
|
myContext, theOuterResource, thePathToElement, (IBaseReference) theElement));
|
||||||
|
@ -310,6 +338,19 @@ public class FhirTerser {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean pathShouldBeExcluded(List<List<String>> theTokenizedPathsToExclude, List<String> thePathToElement) {
|
||||||
|
return theTokenizedPathsToExclude.stream().anyMatch(p -> {
|
||||||
|
// Check whether the path to the element starts with the path to be excluded
|
||||||
|
if (p.size() > thePathToElement.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> prefix = thePathToElement.subList(0, p.size());
|
||||||
|
|
||||||
|
return Objects.equals(p, prefix);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private BaseRuntimeChildDefinition getDefinition(
|
private BaseRuntimeChildDefinition getDefinition(
|
||||||
BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
|
BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
|
||||||
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
|
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
@ -250,34 +251,77 @@ public class OperationOutcomeUtil {
|
||||||
public static IBase addIssueWithMessageId(
|
public static IBase addIssueWithMessageId(
|
||||||
FhirContext myCtx,
|
FhirContext myCtx,
|
||||||
IBaseOperationOutcome theOperationOutcome,
|
IBaseOperationOutcome theOperationOutcome,
|
||||||
String severity,
|
String theSeverity,
|
||||||
String message,
|
String theMessage,
|
||||||
String messageId,
|
String theMessageId,
|
||||||
String location,
|
String theLocation,
|
||||||
String theCode) {
|
String theCode) {
|
||||||
IBase issue = addIssue(myCtx, theOperationOutcome, severity, message, location, theCode);
|
IBase issue = addIssue(myCtx, theOperationOutcome, theSeverity, theMessage, theLocation, theCode);
|
||||||
BaseRuntimeElementCompositeDefinition<?> issueElement =
|
if (isNotBlank(theMessageId)) {
|
||||||
(BaseRuntimeElementCompositeDefinition<?>) myCtx.getElementDefinition(issue.getClass());
|
addDetailsToIssue(myCtx, issue, Constants.JAVA_VALIDATOR_DETAILS_SYSTEM, theMessageId);
|
||||||
BaseRuntimeChildDefinition detailsChildDef = issueElement.getChildByName("details");
|
}
|
||||||
|
|
||||||
IPrimitiveType<?> system =
|
|
||||||
(IPrimitiveType<?>) myCtx.getElementDefinition("uri").newInstance();
|
|
||||||
system.setValueAsString(Constants.JAVA_VALIDATOR_DETAILS_SYSTEM);
|
|
||||||
IPrimitiveType<?> code =
|
|
||||||
(IPrimitiveType<?>) myCtx.getElementDefinition("code").newInstance();
|
|
||||||
code.setValueAsString(messageId);
|
|
||||||
|
|
||||||
BaseRuntimeElementCompositeDefinition<?> codingDef =
|
|
||||||
(BaseRuntimeElementCompositeDefinition<?>) myCtx.getElementDefinition("Coding");
|
|
||||||
ICompositeType coding = (ICompositeType) codingDef.newInstance();
|
|
||||||
codingDef.getChildByName("system").getMutator().addValue(coding, system);
|
|
||||||
codingDef.getChildByName("code").getMutator().addValue(coding, code);
|
|
||||||
BaseRuntimeElementCompositeDefinition<?> ccDef =
|
|
||||||
(BaseRuntimeElementCompositeDefinition<?>) myCtx.getElementDefinition("CodeableConcept");
|
|
||||||
ICompositeType codeableConcept = (ICompositeType) ccDef.newInstance();
|
|
||||||
ccDef.getChildByName("coding").getMutator().addValue(codeableConcept, coding);
|
|
||||||
|
|
||||||
detailsChildDef.getMutator().addValue(issue, codeableConcept);
|
|
||||||
return issue;
|
return issue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addDetailsToIssue(FhirContext theFhirContext, IBase theIssue, String theSystem, String theCode) {
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> issueElement =
|
||||||
|
(BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition(theIssue.getClass());
|
||||||
|
BaseRuntimeChildDefinition detailsChildDef = issueElement.getChildByName("details");
|
||||||
|
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> codingDef =
|
||||||
|
(BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition("Coding");
|
||||||
|
ICompositeType coding = (ICompositeType) codingDef.newInstance();
|
||||||
|
|
||||||
|
// System
|
||||||
|
IPrimitiveType<?> system =
|
||||||
|
(IPrimitiveType<?>) theFhirContext.getElementDefinition("uri").newInstance();
|
||||||
|
system.setValueAsString(theSystem);
|
||||||
|
codingDef.getChildByName("system").getMutator().addValue(coding, system);
|
||||||
|
|
||||||
|
// Code
|
||||||
|
IPrimitiveType<?> code =
|
||||||
|
(IPrimitiveType<?>) theFhirContext.getElementDefinition("code").newInstance();
|
||||||
|
code.setValueAsString(theCode);
|
||||||
|
codingDef.getChildByName("code").getMutator().addValue(coding, code);
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> ccDef =
|
||||||
|
(BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition("CodeableConcept");
|
||||||
|
|
||||||
|
ICompositeType codeableConcept = (ICompositeType) ccDef.newInstance();
|
||||||
|
ccDef.getChildByName("coding").getMutator().addValue(codeableConcept, coding);
|
||||||
|
detailsChildDef.getMutator().addValue(theIssue, codeableConcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addIssueLineExtensionToIssue(FhirContext theCtx, IBase theIssue, String theLine) {
|
||||||
|
if (theCtx.getVersion().getVersion() != FhirVersionEnum.DSTU2) {
|
||||||
|
ExtensionUtil.setExtension(
|
||||||
|
theCtx,
|
||||||
|
theIssue,
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-line",
|
||||||
|
"integer",
|
||||||
|
theLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addIssueColExtensionToIssue(FhirContext theCtx, IBase theIssue, String theColumn) {
|
||||||
|
if (theCtx.getVersion().getVersion() != FhirVersionEnum.DSTU2) {
|
||||||
|
ExtensionUtil.setExtension(
|
||||||
|
theCtx,
|
||||||
|
theIssue,
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-col",
|
||||||
|
"integer",
|
||||||
|
theColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addMessageIdExtensionToIssue(FhirContext theCtx, IBase theIssue, String theMessageId) {
|
||||||
|
if (theCtx.getVersion().getVersion() != FhirVersionEnum.DSTU2) {
|
||||||
|
ExtensionUtil.setExtension(
|
||||||
|
theCtx,
|
||||||
|
theIssue,
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id",
|
||||||
|
"string",
|
||||||
|
theMessageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,7 +403,7 @@ public class ParametersUtil {
|
||||||
public static void addPartDecimal(FhirContext theContext, IBase theParameter, String theName, Double theValue) {
|
public static void addPartDecimal(FhirContext theContext, IBase theParameter, String theName, Double theValue) {
|
||||||
IPrimitiveType<BigDecimal> value = (IPrimitiveType<BigDecimal>)
|
IPrimitiveType<BigDecimal> value = (IPrimitiveType<BigDecimal>)
|
||||||
theContext.getElementDefinition("decimal").newInstance();
|
theContext.getElementDefinition("decimal").newInstance();
|
||||||
value.setValue(theValue == null ? null : new BigDecimal(theValue));
|
value.setValue(theValue == null ? null : BigDecimal.valueOf(theValue));
|
||||||
|
|
||||||
addPart(theContext, theParameter, theName, value);
|
addPart(theContext, theParameter, theName, value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -602,6 +604,39 @@ public class UrlUtil {
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates list of sub URIs candidates for search with :above modifier
|
||||||
|
* Example input: http://[host]/[pathPart1]/[pathPart2]
|
||||||
|
* Example output: http://[host], http://[host]/[pathPart1], http://[host]/[pathPart1]/[pathPart2]
|
||||||
|
*
|
||||||
|
* @param theUri String URI parameter
|
||||||
|
* @return List of URI candidates
|
||||||
|
*/
|
||||||
|
public static List<String> getAboveUriCandidates(String theUri) {
|
||||||
|
try {
|
||||||
|
URI uri = new URI(theUri);
|
||||||
|
if (uri.getScheme() == null || uri.getHost() == null) {
|
||||||
|
throwInvalidRequestExceptionForNotValidUri(theUri, null);
|
||||||
|
}
|
||||||
|
} catch (URISyntaxException theCause) {
|
||||||
|
throwInvalidRequestExceptionForNotValidUri(theUri, theCause);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> candidates = new ArrayList<>();
|
||||||
|
Path path = Paths.get(theUri);
|
||||||
|
candidates.add(path.toString().replace(":/", "://"));
|
||||||
|
while (path.getParent() != null && path.getParent().toString().contains("/")) {
|
||||||
|
candidates.add(path.getParent().toString().replace(":/", "://"));
|
||||||
|
path = path.getParent();
|
||||||
|
}
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void throwInvalidRequestExceptionForNotValidUri(String theUri, Exception theCause) {
|
||||||
|
throw new InvalidRequestException(
|
||||||
|
Msg.code(2419) + String.format("Provided URI is not valid: %s", theUri), theCause);
|
||||||
|
}
|
||||||
|
|
||||||
public static class UrlParts {
|
public static class UrlParts {
|
||||||
private String myParams;
|
private String myParams;
|
||||||
private String myResourceId;
|
private String myResourceId;
|
||||||
|
|
|
@ -117,11 +117,18 @@ public enum VersionEnum {
|
||||||
V6_4_2,
|
V6_4_2,
|
||||||
V6_5_0,
|
V6_5_0,
|
||||||
V6_6_0,
|
V6_6_0,
|
||||||
|
V6_6_1,
|
||||||
|
V6_6_2,
|
||||||
V6_7_0,
|
V6_7_0,
|
||||||
V6_8_0,
|
V6_8_0,
|
||||||
|
V6_8_1,
|
||||||
|
V6_8_2,
|
||||||
V6_9_0,
|
V6_9_0,
|
||||||
|
|
||||||
|
V6_10_0,
|
||||||
|
|
||||||
|
V6_11_0,
|
||||||
|
|
||||||
V7_0_0;
|
V7_0_0;
|
||||||
|
|
||||||
public static VersionEnum latestVersion() {
|
public static VersionEnum latestVersion() {
|
||||||
|
|
|
@ -24,6 +24,8 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SingleValidationMessage {
|
public class SingleValidationMessage {
|
||||||
|
|
||||||
private Integer myLocationCol;
|
private Integer myLocationCol;
|
||||||
|
@ -32,6 +34,7 @@ public class SingleValidationMessage {
|
||||||
private String myMessage;
|
private String myMessage;
|
||||||
private String myMessageId;
|
private String myMessageId;
|
||||||
private ResultSeverityEnum mySeverity;
|
private ResultSeverityEnum mySeverity;
|
||||||
|
private List<String> mySliceMessages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -58,6 +61,7 @@ public class SingleValidationMessage {
|
||||||
b.append(myLocationString, other.myLocationString);
|
b.append(myLocationString, other.myLocationString);
|
||||||
b.append(myMessage, other.myMessage);
|
b.append(myMessage, other.myMessage);
|
||||||
b.append(mySeverity, other.mySeverity);
|
b.append(mySeverity, other.mySeverity);
|
||||||
|
b.append(mySliceMessages, other.mySliceMessages);
|
||||||
return b.isEquals();
|
return b.isEquals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +97,7 @@ public class SingleValidationMessage {
|
||||||
b.append(myLocationString);
|
b.append(myLocationString);
|
||||||
b.append(myMessage);
|
b.append(myMessage);
|
||||||
b.append(mySeverity);
|
b.append(mySeverity);
|
||||||
|
b.append(mySliceMessages);
|
||||||
return b.toHashCode();
|
return b.toHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +142,17 @@ public class SingleValidationMessage {
|
||||||
if (mySeverity != null) {
|
if (mySeverity != null) {
|
||||||
b.append("severity", mySeverity.getCode());
|
b.append("severity", mySeverity.getCode());
|
||||||
}
|
}
|
||||||
|
if (mySliceMessages != null) {
|
||||||
|
b.append("sliceMessages", mySliceMessages);
|
||||||
|
}
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSliceMessages(List<String> theSliceMessages) {
|
||||||
|
mySliceMessages = theSliceMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSliceMessages() {
|
||||||
|
return mySliceMessages;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,11 +39,11 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
*/
|
*/
|
||||||
public class ValidationResult {
|
public class ValidationResult {
|
||||||
public static final int ERROR_DISPLAY_LIMIT_DEFAULT = 1;
|
public static final int ERROR_DISPLAY_LIMIT_DEFAULT = 1;
|
||||||
|
public static final String UNKNOWN = "(unknown)";
|
||||||
|
private static final String ourNewLine = System.getProperty("line.separator");
|
||||||
private final FhirContext myCtx;
|
private final FhirContext myCtx;
|
||||||
private final boolean myIsSuccessful;
|
private final boolean myIsSuccessful;
|
||||||
private final List<SingleValidationMessage> myMessages;
|
private final List<SingleValidationMessage> myMessages;
|
||||||
|
|
||||||
private int myErrorDisplayLimit = ERROR_DISPLAY_LIMIT_DEFAULT;
|
private int myErrorDisplayLimit = ERROR_DISPLAY_LIMIT_DEFAULT;
|
||||||
|
|
||||||
public ValidationResult(FhirContext theCtx, List<SingleValidationMessage> theMessages) {
|
public ValidationResult(FhirContext theCtx, List<SingleValidationMessage> theMessages) {
|
||||||
|
@ -131,39 +132,36 @@ public class ValidationResult {
|
||||||
*/
|
*/
|
||||||
public void populateOperationOutcome(IBaseOperationOutcome theOperationOutcome) {
|
public void populateOperationOutcome(IBaseOperationOutcome theOperationOutcome) {
|
||||||
for (SingleValidationMessage next : myMessages) {
|
for (SingleValidationMessage next : myMessages) {
|
||||||
String location;
|
Integer locationLine = next.getLocationLine();
|
||||||
if (isNotBlank(next.getLocationString())) {
|
Integer locationCol = next.getLocationCol();
|
||||||
location = next.getLocationString();
|
String location = next.getLocationString();
|
||||||
} else if (next.getLocationLine() != null || next.getLocationCol() != null) {
|
ResultSeverityEnum issueSeverity = next.getSeverity();
|
||||||
location = "Line[" + next.getLocationLine() + "] Col[" + next.getLocationCol() + "]";
|
String message = next.getMessage();
|
||||||
} else {
|
String messageId = next.getMessageId();
|
||||||
location = null;
|
|
||||||
}
|
|
||||||
String severity = next.getSeverity() != null ? next.getSeverity().getCode() : null;
|
|
||||||
IBase issue = OperationOutcomeUtil.addIssueWithMessageId(
|
|
||||||
myCtx,
|
|
||||||
theOperationOutcome,
|
|
||||||
severity,
|
|
||||||
next.getMessage(),
|
|
||||||
next.getMessageId(),
|
|
||||||
location,
|
|
||||||
Constants.OO_INFOSTATUS_PROCESSING);
|
|
||||||
|
|
||||||
if (next.getLocationLine() != null || next.getLocationCol() != null) {
|
if (next.getSliceMessages() == null) {
|
||||||
String unknown = "(unknown)";
|
addIssueToOperationOutcome(
|
||||||
String line = unknown;
|
theOperationOutcome, location, locationLine, locationCol, issueSeverity, message, messageId);
|
||||||
if (next.getLocationLine() != null && next.getLocationLine() != -1) {
|
continue;
|
||||||
line = next.getLocationLine().toString();
|
|
||||||
}
|
|
||||||
String col = unknown;
|
|
||||||
if (next.getLocationCol() != null && next.getLocationCol() != -1) {
|
|
||||||
col = next.getLocationCol().toString();
|
|
||||||
}
|
|
||||||
if (!unknown.equals(line) || !unknown.equals(col)) {
|
|
||||||
OperationOutcomeUtil.addLocationToIssue(myCtx, issue, "Line " + line + ", Col " + col);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Occasionally the validator will return these lists of "slice messages"
|
||||||
|
* which happen when validating rules associated with a specific slice in
|
||||||
|
* a profile.
|
||||||
|
*/
|
||||||
|
for (String nextSliceMessage : next.getSliceMessages()) {
|
||||||
|
String combinedMessage = message + " - " + nextSliceMessage;
|
||||||
|
addIssueToOperationOutcome(
|
||||||
|
theOperationOutcome,
|
||||||
|
location,
|
||||||
|
locationLine,
|
||||||
|
locationCol,
|
||||||
|
issueSeverity,
|
||||||
|
combinedMessage,
|
||||||
|
messageId);
|
||||||
}
|
}
|
||||||
|
} // for
|
||||||
|
|
||||||
if (myMessages.isEmpty()) {
|
if (myMessages.isEmpty()) {
|
||||||
String message = myCtx.getLocalizer().getMessage(ValidationResult.class, "noIssuesDetected");
|
String message = myCtx.getLocalizer().getMessage(ValidationResult.class, "noIssuesDetected");
|
||||||
|
@ -171,6 +169,44 @@ public class ValidationResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addIssueToOperationOutcome(
|
||||||
|
IBaseOperationOutcome theOperationOutcome,
|
||||||
|
String location,
|
||||||
|
Integer locationLine,
|
||||||
|
Integer locationCol,
|
||||||
|
ResultSeverityEnum issueSeverity,
|
||||||
|
String message,
|
||||||
|
String messageId) {
|
||||||
|
if (isBlank(location) && locationLine != null && locationCol != null) {
|
||||||
|
location = "Line[" + locationLine + "] Col[" + locationCol + "]";
|
||||||
|
}
|
||||||
|
String severity = issueSeverity != null ? issueSeverity.getCode() : null;
|
||||||
|
IBase issue = OperationOutcomeUtil.addIssueWithMessageId(
|
||||||
|
myCtx, theOperationOutcome, severity, message, messageId, location, Constants.OO_INFOSTATUS_PROCESSING);
|
||||||
|
|
||||||
|
if (locationLine != null || locationCol != null) {
|
||||||
|
String unknown = UNKNOWN;
|
||||||
|
String line = unknown;
|
||||||
|
if (locationLine != null && locationLine != -1) {
|
||||||
|
line = locationLine.toString();
|
||||||
|
}
|
||||||
|
String col = unknown;
|
||||||
|
if (locationCol != null && locationCol != -1) {
|
||||||
|
col = locationCol.toString();
|
||||||
|
}
|
||||||
|
if (!unknown.equals(line) || !unknown.equals(col)) {
|
||||||
|
OperationOutcomeUtil.addIssueLineExtensionToIssue(myCtx, issue, line);
|
||||||
|
OperationOutcomeUtil.addIssueColExtensionToIssue(myCtx, issue, col);
|
||||||
|
String locationString = "Line[" + line + "] Col[" + col + "]";
|
||||||
|
OperationOutcomeUtil.addLocationToIssue(myCtx, issue, locationString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNotBlank(messageId)) {
|
||||||
|
OperationOutcomeUtil.addMessageIdExtensionToIssue(myCtx, issue, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ValidationResult{" + "messageCount=" + myMessages.size() + ", isSuccessful=" + myIsSuccessful
|
return "ValidationResult{" + "messageCount=" + myMessages.size() + ", isSuccessful=" + myIsSuccessful
|
||||||
|
@ -191,6 +227,4 @@ public class ValidationResult {
|
||||||
public void setErrorDisplayLimit(int theErrorDisplayLimit) {
|
public void setErrorDisplayLimit(int theErrorDisplayLimit) {
|
||||||
myErrorDisplayLimit = theErrorDisplayLimit;
|
myErrorDisplayLimit = theErrorDisplayLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String ourNewLine = System.getProperty("line.separator");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
|
||||||
|
org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport.displayMismatch=Concept Display "{0}" does not match expected "{1}"
|
||||||
|
|
||||||
|
|
||||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.expansionRefersToUnknownCs=Unknown CodeSystem URI "{0}" referenced from ValueSet
|
ca.uhn.fhir.jpa.term.TermReadSvcImpl.expansionRefersToUnknownCs=Unknown CodeSystem URI "{0}" referenced from ValueSet
|
||||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetNotYetExpanded=ValueSet "{0}" has not yet been pre-expanded. Performing in-memory expansion without parameters. Current status: {1} | {2}
|
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetNotYetExpanded=ValueSet "{0}" has not yet been pre-expanded. Performing in-memory expansion without parameters. Current status: {1} | {2}
|
||||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetNotYetExpanded_OffsetNotAllowed=ValueSet expansion can not combine "offset" with "ValueSet.compose.exclude" unless the ValueSet has been pre-expanded. ValueSet "{0}" must be pre-expanded for this operation to work.
|
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetNotYetExpanded_OffsetNotAllowed=ValueSet expansion can not combine "offset" with "ValueSet.compose.exclude" unless the ValueSet has been pre-expanded. ValueSet "{0}" must be pre-expanded for this operation to work.
|
||||||
|
@ -8,6 +11,7 @@ ca.uhn.fhir.jpa.term.TermReadSvcImpl.validationPerformedAgainstPreExpansion=Code
|
||||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetNotFoundInTerminologyDatabase=ValueSet can not be found in terminology database: {0}
|
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetNotFoundInTerminologyDatabase=ValueSet can not be found in terminology database: {0}
|
||||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetPreExpansionInvalidated=ValueSet with URL "{0}" precaluclated expansion with {1} concept(s) has been invalidated
|
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetPreExpansionInvalidated=ValueSet with URL "{0}" precaluclated expansion with {1} concept(s) has been invalidated
|
||||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetCantInvalidateNotYetPrecalculated=ValueSet with URL "{0}" already has status: {1}
|
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetCantInvalidateNotYetPrecalculated=ValueSet with URL "{0}" already has status: {1}
|
||||||
|
ca.uhn.fhir.jpa.term.TermReadSvcImpl.unknownCodeInSystem=Unknown code "{0}#{1}"
|
||||||
|
|
||||||
|
|
||||||
# Core Library Messages
|
# Core Library Messages
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-bom</artifactId>
|
<artifactId>hapi-fhir-bom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>HAPI FHIR BOM</name>
|
<name>HAPI FHIR BOM</name>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -270,14 +270,6 @@ public abstract class BaseApp {
|
||||||
|
|
||||||
// Actually execute the command
|
// Actually execute the command
|
||||||
command.run(parsedOptions);
|
command.run(parsedOptions);
|
||||||
|
|
||||||
myShutdownHookHasNotRun = true;
|
|
||||||
runCleanupHookAndUnregister();
|
|
||||||
|
|
||||||
if (!HapiSystemProperties.isTestModeEnabled()) {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
if (!HapiSystemProperties.isTestModeEnabled()) {
|
if (!HapiSystemProperties.isTestModeEnabled()) {
|
||||||
LogbackUtil.loggingConfigOff();
|
LogbackUtil.loggingConfigOff();
|
||||||
|
@ -296,6 +288,13 @@ public abstract class BaseApp {
|
||||||
ourLog.error("Error during execution: ", t);
|
ourLog.error("Error during execution: ", t);
|
||||||
runCleanupHookAndUnregister();
|
runCleanupHookAndUnregister();
|
||||||
exitDueToException(new CommandFailureException("Error: " + t, t));
|
exitDueToException(new CommandFailureException("Error: " + t, t));
|
||||||
|
} finally {
|
||||||
|
myShutdownHookHasNotRun = true;
|
||||||
|
runCleanupHookAndUnregister();
|
||||||
|
|
||||||
|
if (!HapiSystemProperties.isTestModeEnabled()) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-cli</artifactId>
|
<artifactId>hapi-fhir-cli</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -75,8 +75,7 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param theFhirContext
|
* @param theFhirContext The context
|
||||||
* The context
|
|
||||||
*/
|
*/
|
||||||
public RestfulClientFactory(FhirContext theFhirContext) {
|
public RestfulClientFactory(FhirContext theFhirContext) {
|
||||||
myContext = theFhirContext;
|
myContext = theFhirContext;
|
||||||
|
@ -142,13 +141,10 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
||||||
/**
|
/**
|
||||||
* Instantiates a new client instance
|
* Instantiates a new client instance
|
||||||
*
|
*
|
||||||
* @param theClientType
|
* @param theClientType The client type, which is an interface type to be instantiated
|
||||||
* The client type, which is an interface type to be instantiated
|
* @param theServerBase The URL of the base for the restful FHIR server to connect to
|
||||||
* @param theServerBase
|
|
||||||
* The URL of the base for the restful FHIR server to connect to
|
|
||||||
* @return A newly created client
|
* @return A newly created client
|
||||||
* @throws ConfigurationException
|
* @throws ConfigurationException If the interface type is not an interface
|
||||||
* If the interface type is not an interface
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized <T extends IRestfulClient> T newClient(Class<T> theClientType, String theServerBase) {
|
public synchronized <T extends IRestfulClient> T newClient(Class<T> theClientType, String theServerBase) {
|
||||||
|
@ -281,13 +277,8 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ONCE:
|
case ONCE:
|
||||||
if (myValidatedServerBaseUrls.contains(serverBase)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (myValidatedServerBaseUrls) {
|
synchronized (myValidatedServerBaseUrls) {
|
||||||
if (!myValidatedServerBaseUrls.contains(serverBase)) {
|
if (myValidatedServerBaseUrls.add(serverBase)) {
|
||||||
myValidatedServerBaseUrls.add(serverBase);
|
|
||||||
validateServerBase(serverBase, theHttpClient, theClient);
|
validateServerBase(serverBase, theHttpClient, theClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,20 +387,13 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
String serverBase = normalizeBaseUrlForMap(theServerBase);
|
String serverBase = normalizeBaseUrlForMap(theServerBase);
|
||||||
if (myValidatedServerBaseUrls.contains(serverBase)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (myValidatedServerBaseUrls) {
|
|
||||||
myValidatedServerBaseUrls.add(serverBase);
|
myValidatedServerBaseUrls.add(serverBase);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the http client for the given server base
|
* Get the http client for the given server base
|
||||||
*
|
*
|
||||||
* @param theServerBase
|
* @param theServerBase the server base
|
||||||
* the server base
|
|
||||||
* @return the http client
|
* @return the http client
|
||||||
*/
|
*/
|
||||||
protected abstract IHttpClient getHttpClient(String theServerBase);
|
protected abstract IHttpClient getHttpClient(String theServerBase);
|
||||||
|
|
|
@ -544,6 +544,7 @@ public class MethodUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodOutcome retVal = new MethodOutcome();
|
MethodOutcome retVal = new MethodOutcome();
|
||||||
|
retVal.setResponseStatusCode(theResponseStatusCode);
|
||||||
if (locationHeaders.size() > 0) {
|
if (locationHeaders.size() > 0) {
|
||||||
String locationHeader = locationHeaders.get(0);
|
String locationHeader = locationHeaders.get(0);
|
||||||
BaseOutcomeReturningMethodBinding.parseContentLocation(theContext, retVal, locationHeader);
|
BaseOutcomeReturningMethodBinding.parseContentLocation(theContext, retVal, locationHeader);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.9.2-SNAPSHOT</version>
|
<version>6.9.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.method.ResponsePage;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.InstantType;
|
import org.hl7.fhir.r4.model.InstantType;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
@ -63,7 +64,10 @@ public class PagingPatientProvider implements IResourceProvider {
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
public List<IBaseResource> getResources(
|
||||||
|
int theFromIndex,
|
||||||
|
int theToIndex,
|
||||||
|
@Nonnull ResponsePage.ResponsePageBuilder theResponsePageBuilder) {
|
||||||
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
|
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
|
||||||
List<Long> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
|
List<Long> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
|
||||||
return loadResourcesByIds(idsToReturn);
|
return loadResourcesByIds(idsToReturn);
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 3786
|
||||||
|
title: "Previously, when executing an update on a resource that had to undergo MDM, a nullpointer could occur. This has been fixed."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5089
|
||||||
|
title: "Updating storage-cr module to latest CQL 3.0.0, latest cql engine improvements, and Clinical Reasoning operations
|
||||||
|
to leverage repository api pattern. This will remove several dependencies from within hapi-fhir to make future maintenance
|
||||||
|
simpler and performance more robust."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5129
|
||||||
|
title: "Added a field that shows the total number of `POSSIBLE_DUPLICATE` links has been added to the `$mdm-duplicate-golden-resources` operation response."
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5192
|
||||||
|
title: "Fixed a bug where search Bundles with `include` entries from an _include query parameter might
|
||||||
|
trigger a 'next' link to blank pages.
|
||||||
|
Specifically, if _include'd resources + requested resources were greater than (or equal to)
|
||||||
|
requested page size, a 'next' link would be generated, even though no additional
|
||||||
|
resources are available.
|
||||||
|
"
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5196
|
||||||
|
title: "Previously, type-level expunge was allowed even if expunge operation was turned off. This is now fixed."
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5198
|
||||||
|
title: "Resolved an issue with type-everything search operations (eg, /Patient/$everything),
|
||||||
|
where not all page results were being returned if _count was specified to be
|
||||||
|
the same value as the maximum page size to fetch.
|
||||||
|
"
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5212
|
||||||
|
title: "Previously, when a CDS hook was registered and called with a empty context, the server returned a 500. This behaviour has been fixed."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: perf
|
||||||
|
issue: 5215
|
||||||
|
title: "When executing an HFQL search with a FHIRPath filter on the `id` element, this will now
|
||||||
|
be automatically converted into an `_id` search parameter match for better performance."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5219
|
||||||
|
title: "Reindex batch job threw an exception when no results matched the reindex request. This has been corrected."
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5220
|
||||||
|
title: "Fixed a race condition in RestfulClientFactory that could cause validateInitialized() to deadlock.
|
||||||
|
Fixed a race condition in FhirContext initialization that could produce a 'this.myNameToResourceType is null' NPE.
|
||||||
|
Fixed a shutdown hook memory leak in BaseApp that happened when the command threw an exception;
|
||||||
|
this memory leak only affects code that calls App.main repeatedly which is probably only in test code."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5230
|
||||||
|
title: "batch2 jobs on MS SQL Server were failing to transition to FAILED state after max retrials
|
||||||
|
for the job are exhausted. This is now fixed."
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5231
|
||||||
|
title: "Previously, the `$mdm-link-history` operation would result in a 404 response when it was executed after a
|
||||||
|
`$mdm-clear`. This has now been fixed by removing link history on `$mdm-clear`."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5235
|
||||||
|
title: "Changes have been made to allow searching on multiple patient _ids
|
||||||
|
when in a patient_id partitioned environment.
|
||||||
|
"
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5236
|
||||||
|
title: "Previously, when updating an MDM link to NO_MATCH,
|
||||||
|
the golden resource involved would maintain its previous
|
||||||
|
values, as defined by survivorship service.
|
||||||
|
This would result in out-of-date golden resources with
|
||||||
|
data that might not be accurate anymore.
|
||||||
|
Now, when a link is changed to NO_MATCH, golden resources
|
||||||
|
will be rebuilt from the ground up using the MDM survivorship
|
||||||
|
service, and the set of links/source resources available at the
|
||||||
|
time of update.
|
||||||
|
"
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5238
|
||||||
|
title: "Added an implementation of Clinical Reasoning CDS on FHIR to the CDS Hooks module that allows PlanDefinition
|
||||||
|
worfklows to be processed as CDS Services using the $apply operation.
|
||||||
|
"
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5242
|
||||||
|
title: "Previously, `$mdm-clear` failed to expunge `REDIRECTED` golden resources which left them as orphans. This is now fixed."
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5246
|
||||||
|
title: "Combined the ExpandResources step and WriteBinary step in the new WriteBinary step v2 for bulk exports."
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5254
|
||||||
|
title: "Previously, when bulk export is enabled the resource list would be generated and would
|
||||||
|
not be able to add a custom resource to that list. Now once a custom resource is added the list is
|
||||||
|
rebuilt.
|
||||||
|
"
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5256
|
||||||
|
title: "Added RequestDetails as part of the parameters when cleaning up possible matches to enable interceptors to
|
||||||
|
access it."
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
type: change
|
||||||
|
issue: 5229
|
||||||
|
title: "Previously, when using INLINE tag storage mode, a superfluous version of a resource would be created as a result
|
||||||
|
of an update request which didn't have a real logical change to the resource but only changed the order of existing
|
||||||
|
items in tag, security label or profile collections. This change prevents this behaviour. Also on resource retrieval,
|
||||||
|
these meta collections are sorted alphabetically, based on (security, code) pair for tags and security labels."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: change
|
||||||
|
issue: 5262
|
||||||
|
title: "Previously, when both resourceId and goldenResourceId are provided to the mdm link history operation, they will
|
||||||
|
be treated as an OR. This is now changed to AND in order to comply with REST conventions."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
jira: SMILE-7307
|
||||||
|
title: "Previously, executing a Group Bulk Export without defining the `_type` parameter would accidentally omit `Patient` and `Organization` types. This has been corrected."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5268
|
||||||
|
title: "Previously, the response status code set in a `MethodOutcome` of a Resource provider was not respected.
|
||||||
|
This has been fixed."
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5271
|
||||||
|
title: "The error messages returned in an OperationOutcome when validating terminology codes
|
||||||
|
as a part of resource profile validation have been improved. Machine processable location
|
||||||
|
(line/col) information is now available through a pair of dedicated extensions, and
|
||||||
|
error messages such as UCUM parsing issues are now returned to the client (previously
|
||||||
|
they were swallowed and a generic error message was returned)."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5274
|
||||||
|
title: "Added a service for generating metrics on mdm links and resources.
|
||||||
|
This includes JPA queries and updated indices.
|
||||||
|
"
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5275
|
||||||
|
title: "Added an API that allows to configure permission rules for operations with access to all resources.
|
||||||
|
This permission is needed to allow a search across the entire patient's record in the scope of the $everything operation to access all
|
||||||
|
resources that references input Patient, including resources outside of the patient's compartment."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5275
|
||||||
|
title: "Previously, when calling `$everything` operation on a Patient instance, it was possible to retrieve data related
|
||||||
|
to another patient via a List or Group resources. This has been fixed."
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5276
|
||||||
|
title: "Previously, GraphQL queries will error when using base resource search parameters such as '_id' after search parameter rebuild.
|
||||||
|
This has been fixed."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5290
|
||||||
|
title: "Added storage property to prevent conditional updates from invalidating match criteria."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5295
|
||||||
|
title: "A regression in the HAPI FHIR 6.6.0 JPA server meant that absolute resource
|
||||||
|
references which also contained an identifier were rejected even if the server
|
||||||
|
was configured to allow absolute references. This has been corrected."
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5297
|
||||||
|
title: "Several fixes have been made to the IPS generator:
|
||||||
|
<ul>
|
||||||
|
<li>The display names associated with several sections have been corrected to exactly match the LOINC definitions for their codes</li>
|
||||||
|
<li>Immunizations will now be ordered from most recent to least recent</li>
|
||||||
|
<li>IPS documents containing Consent resources for Advanced Directives could result in a crash</li>
|
||||||
|
<li>IPS documents containing Procedure resources for History of Procedures with a performed date could result in a crash</li>
|
||||||
|
<li>IPS documents containing AllergyIntolerance resources containing an occurrence but not a reaction date could result in a crash</li>
|
||||||
|
<li>IPS documents containing AllergyIntolerance resources containing an onset value in string format could result in a crash</li>
|
||||||
|
<li>IPS documents containing MedicationRequest resources with no associated Medication could result in a crash</li>
|
||||||
|
</ul>"
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5298
|
||||||
|
title: "Under some circumstances, a large `$everything` operation could enter an infinite loop and eventually timeout with a failure. This has been corrected."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5300
|
||||||
|
title: "A bug in DefaultProfileValidationSupport in R5 mode caused it to return duplicates
|
||||||
|
in the lists returned by `fetchAllStructureDefinitions()`, `fetchAllSearchParameters()`, etc.
|
||||||
|
This has been corrected."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5300
|
||||||
|
title: "A new configuration option has been added to `StorageSettings` which enables
|
||||||
|
support in the JPA server for the `_language` SearchParameter."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5306
|
||||||
|
title: "A new option has been added to the JPA server JpaStorageOptions which prevents the
|
||||||
|
server from maintaining a version history. In this mode, when a new version of a resource
|
||||||
|
is added, the previous version is automatically expunged."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5307
|
||||||
|
title: "Some search parameters include parenthetical expressions (e.g. `(MedicationRequest.medication as Reference)`).
|
||||||
|
The leading `(` was causing searches using parenthetical expressions to fail where the reference target was a contained resource.
|
||||||
|
This has been corrected."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5310
|
||||||
|
title: "Update DSTU2 tags and security labels with support for `userSelected` and `version` elements.
|
||||||
|
Also fix them on security labels in JPA storage."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5312
|
||||||
|
jira: SMILE-7323
|
||||||
|
title: "Previously, issuing a reindex operation for resources on a specific partition would fail. This problem has been fixed."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5316
|
||||||
|
jira: SMILE-7168
|
||||||
|
title: "Previously, performing a FHIR transaction containing both a conditional delete and a conditional update
|
||||||
|
on the same resource would fail. This has been fixed."
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5321
|
||||||
|
title: "It is now possible to configure the strictness of concept display name validation
|
||||||
|
using a new flag on the InMemoryTerminologyServerValidationSupport (for non-JPA validation)
|
||||||
|
and JpaStorageSettings (for JPA validation). In addition, the error messages emitted by
|
||||||
|
the validator when a concept display doesn't match have been improved to be much
|
||||||
|
more useful."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5322
|
||||||
|
title: "Update DSTU3 validation resources to FHIR 3.0.2 instead of 3.0.1"
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5330
|
||||||
|
jira: SMILE-7372
|
||||||
|
title: "Previously, the capability statement returned by the server would not declare conformance to IG when a bulk data
|
||||||
|
export provider is registered with the server. This issue has been fixed."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5331
|
||||||
|
title: "Previously, the score field returned by $mdm-query-links operation would contain imprecise decimal values. This
|
||||||
|
is now fixed and rounded to 4 decimal places."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5333
|
||||||
|
jira: SMILE-7403
|
||||||
|
title: "A regression was introduced in 2023.08.R01 which caused binary storage prefixes to not be applied to exported binary blobs. This has been fixed."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5336
|
||||||
|
jira: SMILE-7406
|
||||||
|
title: "Previously, on PostgreSQL, the $mdm-link-history operation would fail if all ids provided to a parameter are
|
||||||
|
unknown, and the error will persist for all subsequent requests. This is now fixed."
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5339
|
||||||
|
jira: SMILE-7236
|
||||||
|
title: "Previously, Bulk Export will error when processing a resource if the patient compartment SearchParameter of that resource is not present.
|
||||||
|
This has been fixed, the new behaviour is to ignore such resources."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5341
|
||||||
|
title: "Added registries for CdsCrServices and CrDiscoveryServices in CDS Hooks to allow registration of custom services."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5344
|
||||||
|
jira: SMILE-7324
|
||||||
|
title: "Previously, issuing an expunge operation for resources on a specific partition would fail. This problem has been fixed."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5349
|
||||||
|
title: "Removed duplicate helperSvc bean in JpaConfig (also defined in imported MdmJpaConfig) to resolve BeanDefinitionOverrideException"
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5353
|
||||||
|
jira: SMILE-7451
|
||||||
|
title: "Previously, when using revincludes and includes with iterate, while also using revincludes without iterate,
|
||||||
|
the result omitted some resources that should have been included. This issue has now been fixed."
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5355
|
||||||
|
title: "The generated OpenAPI documentation produced by OpenApiInterceptor will now include
|
||||||
|
additional details in the individual resource type documentation, including the values of
|
||||||
|
*CapabilityStatement.rest.resource.documentation*,
|
||||||
|
*CapabilityStatement.rest.resource.profile*, and
|
||||||
|
*CapabilityStatement.rest.resource.supportedProfile*."
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5356
|
||||||
|
title: "Clinical reasoning bug that did not invalidate resources in repository api global caches for terminology and libraries when updates/deletes were made."
|
|
@ -8,4 +8,8 @@
|
||||||
<li>Flexmark (All): 0.50.40 -> 0.64.8</li>
|
<li>Flexmark (All): 0.50.40 -> 0.64.8</li>
|
||||||
<li>Logback (All): 1.4.4 -> 1.4.7</li>
|
<li>Logback (All): 1.4.4 -> 1.4.7</li>
|
||||||
<li>H2 Database (JPA): 2.1.214 -> 2.2.220</li>
|
<li>H2 Database (JPA): 2.1.214 -> 2.2.220</li>
|
||||||
|
<li>Thymeleaf (Testpage Overlay): 3.0.14.RELEASE -> 3.1.2.RELEASE</li>
|
||||||
|
<li>xpp3 (All): 1.1.4c.0 -> 1.1.6</li>
|
||||||
|
<li>HtmlUnit (All): 2.67.0 -> 2.70.0</li>
|
||||||
|
<li>org.hl7.fhir.core (All): 6.0.22.2 -> 6.1.2</li>
|
||||||
</ul>"
|
</ul>"
|
|
@ -0,0 +1,26 @@
|
||||||
|
This release introduces significant a change to the mechanism performing submission of resource modification events
|
||||||
|
to the message broker. Previously, an event would be submitted as part of the synchronous transaction
|
||||||
|
modifying a resource. Synchronous submission yielded responsive publishing with the caveat that events would be dropped
|
||||||
|
upon submission failure.
|
||||||
|
|
||||||
|
We have replaced the synchronous mechanism with a two stage process. Events are initially stored in
|
||||||
|
database upon completion of the transaction and subsequently submitted to the broker by a scheduled task.
|
||||||
|
This new asynchronous submission mechanism will introduce a slight delay in event publishing. It is our view that such
|
||||||
|
delay is largely compensated by the capability to retry submission upon failure which will eliminate event losses.
|
||||||
|
|
||||||
|
|
||||||
|
There are some potentially breaking changes:
|
||||||
|
* On resource retrieval and before storage, tags, security label and profile collections in resource meta will be
|
||||||
|
sorted in lexicographical order. The order of the elements for Coding types (i.e. tags and security labels) is defined
|
||||||
|
by the (security, code) pair of each element. This normally should not break any clients because these properties are
|
||||||
|
sets according to the FHIR specification, and hence the order of the elements in these collections should not matter.
|
||||||
|
Also with this change the following side effects can be observed:
|
||||||
|
- If using INLINE tag storage mode, the first update request to a resource which has tags, security
|
||||||
|
labels or profiles could create a superfluous resource version if the update request does not really introduce any
|
||||||
|
change to the resource. This is because the persisted tags, security labels, and profile may not be sorted in
|
||||||
|
lexicographical order, and this would be interpreted as a new resource version since the tags would be sorted
|
||||||
|
before storage after this change. If the update request actually changes the resource, there is no concern here.
|
||||||
|
Also, subsequent updates will not create an additional version because of ordering of the meta properties anymore.
|
||||||
|
- These meta collections are sorted in place by the storage layer before persisting the resource, so any piece of
|
||||||
|
code that is calling storage layer directly should not be passing in unmodifiable collections, as it would
|
||||||
|
result in an error.
|
|
@ -1,3 +1,3 @@
|
||||||
---
|
---
|
||||||
release-date: "2022-02-18"
|
release-date: "2022-02-18"
|
||||||
codename: "TBD"
|
codename: "Vishwa"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue