From 9b938262e6081f536541f003e0589c93d5c6e61f Mon Sep 17 00:00:00 2001
From: Patrick Werner
Date: Wed, 10 Jul 2019 16:31:22 +0200
Subject: [PATCH 01/10] fixed nostore -> no-store
---
src/site/xdoc/doc_jpa.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/site/xdoc/doc_jpa.xml b/src/site/xdoc/doc_jpa.xml
index dfee8e9ab03..6628949f4e1 100644
--- a/src/site/xdoc/doc_jpa.xml
+++ b/src/site/xdoc/doc_jpa.xml
@@ -276,7 +276,7 @@ public DaoConfig daoConfig() {
If the client knows that they will only want a small number of results
(for example, a UI containing 20 results is being shown and the client
knows that they will never load the next page of results) the client
- may also use the nostore directive along with a HAPI FHIR
+ may also use the no-store directive along with a HAPI FHIR
extension called max-results in order to specify that
only the given number of results should be fetched. This directive
disabled paging entirely for the request and causes the request to
@@ -285,7 +285,7 @@ public DaoConfig daoConfig() {
From 32a8e1aeaddb82708c7bb4b9f2de760939d32e33 Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Thu, 11 Jul 2019 16:28:50 -0400
Subject: [PATCH 02/10] Omit extensions when encoding in summary mode (except
for CapabilityStatement)
---
.../java/ca/uhn/fhir/parser/BaseParser.java | 35 +++++-
.../java/ca/uhn/fhir/parser/JsonParser.java | 116 ++++++++++++------
.../java/ca/uhn/fhir/parser/XmlParser.java | 8 +-
.../model/api/IBaseHasExtensions.java | 2 +-
.../uhn/fhir/parser/JsonParserDstu3Test.java | 66 +++++++++-
.../uhn/fhir/parser/XmlParserDstu3Test.java | 30 +++++
src/changes/changes.xml | 4 +
7 files changed, 208 insertions(+), 53 deletions(-)
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
index 939f9d2ceeb..ba8b7754c2f 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
@@ -34,6 +34,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hl7.fhir.instance.model.api.*;
+import javax.annotation.Nullable;
import java.io.*;
import java.lang.reflect.Modifier;
import java.util.*;
@@ -65,6 +66,7 @@ public abstract class BaseParser implements IParser {
private boolean mySummaryMode;
private boolean mySuppressNarratives;
private Set myDontStripVersionsFromReferencesAtPaths;
+
/**
* Constructor
*/
@@ -165,8 +167,6 @@ public abstract class BaseParser implements IParser {
myNext = null;
} else if (!myNext.shouldBeEncoded(theContainedResource)) {
myNext = null;
- } else if (isSummaryMode() && !myNext.getDef().isSummary()) {
- myNext = null;
} else if (myNext.getDef() instanceof RuntimeChildNarrativeDefinition) {
if (isSuppressNarratives() || isSummaryMode()) {
myNext = null;
@@ -1004,7 +1004,7 @@ public abstract class BaseParser implements IParser {
private final RuntimeResourceDefinition myResDef;
private final EncodeContext myEncodeContext;
- public CompositeChildElement(CompositeChildElement theParent, BaseRuntimeChildDefinition theDef, EncodeContext theEncodeContext) {
+ public CompositeChildElement(CompositeChildElement theParent, @Nullable BaseRuntimeChildDefinition theDef, EncodeContext theEncodeContext) {
myDef = theDef;
myParent = theParent;
myResDef = null;
@@ -1015,7 +1015,9 @@ public abstract class BaseParser implements IParser {
StringBuilder path = theParent.buildPath();
if (path != null) {
path.append('.');
- path.append(myDef.getElementName());
+ if (myDef != null) {
+ path.append(myDef.getElementName());
+ }
ourLog.trace(" * Next path: {}", path.toString());
}
}
@@ -1165,6 +1167,21 @@ public abstract class BaseParser implements IParser {
if (theContainedResource) {
retVal = !notEncodeForContainedResource.contains(myDef.getElementName());
}
+ if (retVal && isSummaryMode() && (getDef() == null || !getDef().isSummary())) {
+ String resourceName = myEncodeContext.getLeafResourceName();
+ // Technically the spec says we shouldn't include extensions in CapabilityStatement
+ // but we will do so because there are people who depend on this behaviour, at least
+ // as of 2019-07. See
+ // https://github.com/smart-on-fhir/Swift-FHIR/issues/26
+ // for example.
+ if (("Conformance".equals(resourceName) || "CapabilityStatement".equals(resourceName)) &&
+ ("extension".equals(myDef.getElementName()) || "extension".equals(myEncodeContext.getLeafElementName())
+ )) {
+ // skip
+ } else {
+ retVal = false;
+ }
+ }
return retVal;
}
@@ -1183,7 +1200,7 @@ public abstract class BaseParser implements IParser {
@Override
public String toString() {
- return myPath.stream().map(t->t.toString()).collect(Collectors.joining("."));
+ return myPath.stream().map(t -> t.toString()).collect(Collectors.joining("."));
}
protected List getPath() {
@@ -1251,6 +1268,14 @@ public abstract class BaseParser implements IParser {
return myResourcePath;
}
+ public String getLeafElementName() {
+ return getPath().get(getPath().size() - 1).getName();
+ }
+
+ public String getLeafResourceName() {
+ return myResourcePath.get(myResourcePath.size() - 1).getName();
+ }
+
public String getLeafResourcePathFirstField() {
String retVal = null;
for (int i = getPath().size() - 1; i >= 0; i--) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
index 92d109798b6..76fd4347839 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
@@ -80,7 +80,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
theListToAddTo.add(null);
}
if (theListToAddTo.get(valueIdx) == null) {
- theListToAddTo.set(valueIdx, new ArrayList());
+ theListToAddTo.set(valueIdx, new ArrayList<>());
}
theListToAddTo.get(valueIdx).addAll(theCommentsToAdd);
return true;
@@ -89,21 +89,34 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
private boolean addToHeldExtensions(int valueIdx, List extends IBaseExtension, ?>> ext, ArrayList> list, boolean theIsModifier, CompositeChildElement theChildElem,
- CompositeChildElement theParent) {
+ CompositeChildElement theParent, EncodeContext theEncodeContext, boolean theContainedResource, IBase theContainingElement) {
+ boolean retVal = false;
if (ext.size() > 0) {
- list.ensureCapacity(valueIdx);
- while (list.size() <= valueIdx) {
- list.add(null);
- }
- if (list.get(valueIdx) == null) {
- list.set(valueIdx, new ArrayList());
- }
+ Boolean encodeExtension = null;
for (IBaseExtension, ?> next : ext) {
- list.get(valueIdx).add(new HeldExtension(next, theIsModifier, theChildElem, theParent));
+
+ // Make sure we respect _summary and _elements
+ if (encodeExtension == null) {
+ encodeExtension = isEncodeExtension(theParent, theEncodeContext, theContainedResource, theContainingElement);
+ }
+
+ if (encodeExtension) {
+ HeldExtension extension = new HeldExtension(next, theIsModifier, theChildElem, theParent);
+ list.ensureCapacity(valueIdx);
+ while (list.size() <= valueIdx) {
+ list.add(null);
+ }
+ ArrayList extensionList = list.get(valueIdx);
+ if (extensionList == null) {
+ extensionList = new ArrayList<>();
+ list.set(valueIdx, extensionList);
+ }
+ extensionList.add(extension);
+ retVal = true;
+ }
}
- return true;
}
- return false;
+ return retVal;
}
private void addToHeldIds(int theValueIdx, ArrayList theListToAddTo, String theId) {
@@ -342,7 +355,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
if (nextChildElem.getDef().getElementName().equals("extension") || nextChildElem.getDef().getElementName().equals("modifierExtension")
|| nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
if (!haveWrittenExtensions) {
- extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource, nextChildElem, theParent, theEncodeContext);
+ extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource, nextChildElem, theParent, theEncodeContext, theContainedResource);
haveWrittenExtensions = true;
}
continue;
@@ -433,20 +446,20 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
if (primitive) {
if (nextValue instanceof ISupportsUndeclaredExtensions) {
List ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
- force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem, theParent);
+ force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem, theParent, theEncodeContext, theContainedResource, theElement);
ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredModifierExtensions();
- force |= addToHeldExtensions(valueIdx, ext, modifierExtensions, true, nextChildElem, theParent);
+ force |= addToHeldExtensions(valueIdx, ext, modifierExtensions, true, nextChildElem, theParent, theEncodeContext, theContainedResource, theElement);
} else {
if (nextValue instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) nextValue;
List extends IBaseExtension, ?>> ext = element.getExtension();
- force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem, theParent);
+ force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem, theParent, theEncodeContext, theContainedResource, theElement);
}
if (nextValue instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
List extends IBaseExtension, ?>> ext = element.getModifierExtension();
- force |= addToHeldExtensions(valueIdx, ext, extensions, true, nextChildElem, theParent);
+ force |= addToHeldExtensions(valueIdx, ext, extensions, true, nextChildElem, theParent, theEncodeContext, theContainedResource, theElement);
}
}
if (nextValue.hasFormatComment()) {
@@ -486,6 +499,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
theEventWriter.endArray();
}
+
if (!extensions.isEmpty() || !modifierExtensions.isEmpty() || !comments.isEmpty()) {
if (inArray) {
// If this is a repeatable field, the extensions go in an array too
@@ -541,7 +555,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
theEventWriter.endArray();
}
- writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts, theEncodeContext);
+ writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts, theEncodeContext, theContainedResource);
if (inArray) {
theEventWriter.endObject();
}
@@ -626,7 +640,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
final List extensions = new ArrayList<>(0);
final List modifierExtensions = new ArrayList<>(0);
// Undeclared extensions
- extractUndeclaredExtensions(theResourceId, extensions, modifierExtensions, null, null);
+ extractUndeclaredExtensions(theResourceId, extensions, modifierExtensions, null, null, theEncodeContext, theContainedResource);
boolean haveExtension = false;
if (!extensions.isEmpty()) {
haveExtension = true;
@@ -638,7 +652,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
writeCommentsPreAndPost(theResourceId, theEventWriter);
}
if (haveExtension) {
- writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext);
+ writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext, theContainedResource);
}
theEventWriter.endObject();
}
@@ -741,12 +755,12 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
* called _name): resource extensions, and extension extensions
*/
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonLikeWriter theEventWriter, BaseRuntimeElementDefinition> theElementDef, RuntimeResourceDefinition theResDef,
- IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent, EncodeContext theEncodeContext) throws IOException {
+ IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent, EncodeContext theEncodeContext, boolean theContainedResource) throws IOException {
List extensions = new ArrayList<>(0);
List modifierExtensions = new ArrayList<>(0);
// Undeclared extensions
- extractUndeclaredExtensions(theElement, extensions, modifierExtensions, theChildElem, theParent);
+ extractUndeclaredExtensions(theElement, extensions, modifierExtensions, theChildElem, theParent, theEncodeContext, theContainedResource);
// Declared extensions
if (theElementDef != null) {
@@ -754,7 +768,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
// Write the extensions
- writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext);
+ writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext, theContainedResource);
}
private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition> resDef, List extensions, List modifierExtensions,
@@ -782,7 +796,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
private void extractUndeclaredExtensions(IBase theElement, List extensions, List modifierExtensions, CompositeChildElement theChildElem,
- CompositeChildElement theParent) {
+ CompositeChildElement theParent, EncodeContext theEncodeContext, boolean theContainedResource) {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions element = (ISupportsUndeclaredExtensions) theElement;
List ext = element.getUndeclaredExtensions();
@@ -804,11 +818,21 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
if (theElement instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) theElement;
List extends IBaseExtension, ?>> ext = element.getExtension();
+ Boolean encodeExtension = null;
for (IBaseExtension, ?> next : ext) {
if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) {
continue;
}
- extensions.add(new HeldExtension(next, false, theChildElem, theParent));
+
+ // Make sure we respect _elements and _summary
+ if (encodeExtension == null) {
+ encodeExtension = isEncodeExtension(theParent, theEncodeContext, theContainedResource, element);
+ }
+ if (encodeExtension) {
+ HeldExtension extension = new HeldExtension(next, false, theChildElem, theParent);
+ extensions.add(extension);
+ }
+
}
}
if (theElement instanceof IBaseHasModifierExtensions) {
@@ -818,12 +842,23 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
if (next == null || next.isEmpty()) {
continue;
}
- modifierExtensions.add(new HeldExtension(next, true, theChildElem, theParent));
+
+ HeldExtension extension = new HeldExtension(next, true, theChildElem, theParent);
+ modifierExtensions.add(extension);
}
}
}
}
+ private boolean isEncodeExtension(CompositeChildElement theParent, EncodeContext theEncodeContext, boolean theContainedResource, IBase theElement) {
+ theEncodeContext.pushPath("extension", false);
+ BaseRuntimeChildDefinition childDef = ((BaseRuntimeElementCompositeDefinition) myContext.getElementDefinition(theElement.getClass())).getChildByName("extension");
+ CompositeChildElement c = new CompositeChildElement(theParent, childDef, theEncodeContext);
+ boolean retVal = c.shouldBeEncoded(theContainedResource);
+ theEncodeContext.popPath();
+ return retVal;
+ }
+
@Override
public EncodingEnum getEncoding() {
return EncodingEnum.JSON;
@@ -1275,21 +1310,24 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonLikeWriter theEventWriter, RuntimeResourceDefinition resDef, List extensions,
- List modifierExtensions, EncodeContext theEncodeContext) throws IOException {
+ List modifierExtensions, EncodeContext theEncodeContext, boolean theContainedResource) throws IOException {
+ // Write Extensions
if (extensions.isEmpty() == false) {
theEncodeContext.pushPath("extension", false);
beginArray(theEventWriter, "extension");
for (HeldExtension next : extensions) {
- next.write(resDef, theResource, theEventWriter, theEncodeContext);
+ next.write(resDef, theResource, theEventWriter, theEncodeContext, theContainedResource);
}
theEventWriter.endArray();
theEncodeContext.popPath();
}
+
+ // Write ModifierExtensions
if (modifierExtensions.isEmpty() == false) {
theEncodeContext.pushPath("modifierExtension", false);
beginArray(theEventWriter, "modifierExtension");
for (HeldExtension next : modifierExtensions) {
- next.write(resDef, theResource, theEventWriter, theEncodeContext);
+ next.write(resDef, theResource, theEventWriter, theEncodeContext, theContainedResource);
}
theEventWriter.endArray();
theEncodeContext.popPath();
@@ -1353,12 +1391,12 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
return url1.compareTo(url2);
}
- private void managePrimitiveExtension(final IBase theValue, final RuntimeResourceDefinition theResDef, final IBaseResource theResource, final JsonLikeWriter theEventWriter, final BaseRuntimeElementDefinition> def, final String childName, EncodeContext theEncodeContext) throws IOException {
+ private void managePrimitiveExtension(final IBase theValue, final RuntimeResourceDefinition theResDef, final IBaseResource theResource, final JsonLikeWriter theEventWriter, final BaseRuntimeElementDefinition> def, final String childName, EncodeContext theEncodeContext, boolean theContainedResource) throws IOException {
if (def.getChildType().equals(ID_DATATYPE) || def.getChildType().equals(PRIMITIVE_DATATYPE)) {
final List extensions = new ArrayList(0);
final List modifierExtensions = new ArrayList(0);
// Undeclared extensions
- extractUndeclaredExtensions(theValue, extensions, modifierExtensions, myParent, null);
+ extractUndeclaredExtensions(theValue, extensions, modifierExtensions, myParent, null, theEncodeContext, theContainedResource);
// Declared extensions
if (def != null) {
extractDeclaredExtensions(theValue, def, extensions, modifierExtensions, myParent);
@@ -1369,15 +1407,15 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
if (haveContent) {
beginObject(theEventWriter, '_' + childName);
- writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext);
+ writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext, theContainedResource);
theEventWriter.endObject();
}
}
}
- public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, EncodeContext theEncodeContext) throws IOException {
+ public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, EncodeContext theEncodeContext, boolean theContainedResource) throws IOException {
if (myUndeclaredExtension != null) {
- writeUndeclaredExtension(theResDef, theResource, theEventWriter, myUndeclaredExtension, theEncodeContext);
+ writeUndeclaredExtension(theResDef, theResource, theEventWriter, myUndeclaredExtension, theEncodeContext, theContainedResource);
} else {
theEventWriter.beginObject();
@@ -1410,18 +1448,18 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
BaseRuntimeElementDefinition> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
- extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, myChildElem, null, theEncodeContext);
+ extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, myChildElem, null, theEncodeContext, theContainedResource);
} else {
String childName = myDef.getChildNameByDatatype(myValue.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, myParent, false, theEncodeContext);
- managePrimitiveExtension(myValue, theResDef, theResource, theEventWriter, def, childName, theEncodeContext);
+ managePrimitiveExtension(myValue, theResDef, theResource, theEventWriter, def, childName, theEncodeContext, theContainedResource);
}
theEventWriter.endObject();
}
}
- private void writeUndeclaredExtension(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBaseExtension, ?> ext, EncodeContext theEncodeContext) throws IOException {
+ private void writeUndeclaredExtension(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBaseExtension, ?> ext, EncodeContext theEncodeContext, boolean theContainedResource) throws IOException {
IBase value = ext.getValue();
final String extensionUrl = getExtensionUrl(ext.getUrl());
@@ -1465,7 +1503,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
for (Object next : ext.getExtension()) {
- writeUndeclaredExtension(theResDef, theResource, theEventWriter, (IBaseExtension, ?>) next, theEncodeContext);
+ writeUndeclaredExtension(theResDef, theResource, theEventWriter, (IBaseExtension, ?>) next, theEncodeContext, theContainedResource);
}
theEventWriter.endArray();
@@ -1490,7 +1528,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
}
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, false, myParent,false, theEncodeContext);
- managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName, theEncodeContext);
+ managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName, theEncodeContext, theContainedResource);
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
index a0cf79b2df3..ebd305e4a47 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
@@ -51,15 +51,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* This class is the FHIR XML parser/encoder. Users should not interact with this class directly, but should use
* {@link FhirContext#newXmlParser()} to get an instance.
*/
-public class XmlParser extends BaseParser /* implements IParser */ {
+public class XmlParser extends BaseParser {
- static final String ATOM_NS = "http://www.w3.org/2005/Atom";
static final String FHIR_NS = "http://hl7.org/fhir";
- static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearch/1.1/";
- static final String RESREF_DISPLAY = "display";
- static final String RESREF_REFERENCE = "reference";
- static final String TOMBSTONES_NS = "http://purl.org/atompub/tombstones/1.0";
- static final String XHTML_NS = "http://www.w3.org/1999/xhtml";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class);
// private static final Set RESOURCE_NAMESPACES;
diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasExtensions.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasExtensions.java
index 4a1cd1e1361..46ecf64a4c0 100644
--- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasExtensions.java
+++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseHasExtensions.java
@@ -22,7 +22,7 @@ package org.hl7.fhir.instance.model.api;
import java.util.List;
-public interface IBaseHasExtensions {
+public interface IBaseHasExtensions extends IBase {
IBaseExtension, ?> addExtension();
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
index 808bd102918..9256172561d 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
@@ -715,13 +715,26 @@ public class JsonParserDstu3Test {
.setValue(new Reference("Practitioner/A"));
IParser parser = ourCtx.newJsonParser().setPrettyPrint(true);
- parser.setDontEncodeElements(new HashSet(Arrays.asList("*.id", "*.meta")));
+ parser.setDontEncodeElements(new HashSet<>(Arrays.asList("*.id", "*.meta")));
String encoded = parser.encodeResourceToString(p);
ourLog.info(encoded);
assertThat(encoded, containsString("http://foo"));
assertThat(encoded, containsString("Practitioner/A"));
+
+ // Now with exclude
+
+ parser = ourCtx.newJsonParser().setPrettyPrint(true);
+ parser.setDontEncodeElements(new HashSet<>(Arrays.asList("*.id", "*.meta", "*.extension")));
+
+ encoded = parser.encodeResourceToString(p);
+ ourLog.info(encoded);
+
+ assertThat(encoded, (containsString("http://foo")));
+ assertThat(encoded, (containsString("Practitioner/A")));
+
+
}
@Test
@@ -1064,6 +1077,57 @@ public class JsonParserDstu3Test {
assertThat(encoded, not(containsString("maritalStatus")));
}
+ /**
+ * We specifically include extensions on CapabilityStatment even in
+ * summary mode, since this is behaviour that people depend on
+ */
+ @Test
+ public void testEncodeSummaryCapabilityStatementExtensions() {
+
+ CapabilityStatement cs = new CapabilityStatement();
+ CapabilityStatement.CapabilityStatementRestComponent rest = cs.addRest();
+ rest.setMode(CapabilityStatement.RestfulCapabilityMode.CLIENT);
+ rest.getSecurity()
+ .addExtension()
+ .setUrl("http://foo")
+ .setValue(new StringType("bar"));
+
+ cs.getVersionElement().addExtension()
+ .setUrl("http://goo")
+ .setValue(new StringType("ber"));
+
+ String encoded = ourCtx.newJsonParser().setSummaryMode(true).setPrettyPrint(true).setPrettyPrint(true).encodeResourceToString(cs);
+ ourLog.info(encoded);
+
+ assertThat(encoded, (containsString("http://foo")));
+ assertThat(encoded, (containsString("bar")));
+ assertThat(encoded, (containsString("http://goo")));
+ assertThat(encoded, (containsString("ber")));
+ }
+
+ @Test
+ public void testEncodeSummaryPatientExtensions() {
+
+ Patient cs = new Patient();
+ Address address = cs.addAddress();
+ address.setCity("CITY");
+ address
+ .addExtension()
+ .setUrl("http://foo")
+ .setValue(new StringType("bar"));
+ address.getCityElement().addExtension()
+ .setUrl("http://goo")
+ .setValue(new StringType("ber"));
+
+ String encoded = ourCtx.newJsonParser().setSummaryMode(true).setPrettyPrint(true).setPrettyPrint(true).encodeResourceToString(cs);
+ ourLog.info(encoded);
+
+ assertThat(encoded, not(containsString("http://foo")));
+ assertThat(encoded, not(containsString("bar")));
+ assertThat(encoded, not(containsString("http://goo")));
+ assertThat(encoded, not(containsString("ber")));
+ }
+
@Test
public void testEncodeSummary2() {
Patient patient = new Patient();
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
index 15c77074645..d44704e9365 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
@@ -12,6 +12,7 @@ import com.google.common.collect.Sets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
+import org.hamcrest.Matchers;
import org.hamcrest.collection.IsEmptyCollection;
import org.hamcrest.core.StringContains;
import org.hamcrest.text.StringContainsInOrder;
@@ -69,6 +70,35 @@ public class XmlParserDstu3Test {
ourCtx.setNarrativeGenerator(null);
}
+ /**
+ * We specifically include extensions on CapabilityStatment even in
+ * summary mode, since this is behaviour that people depend on
+ */
+ @Test
+ public void testEncodeSummaryCapabilityStatementExtensions() {
+
+ CapabilityStatement cs = new CapabilityStatement();
+ CapabilityStatement.CapabilityStatementRestComponent rest = cs.addRest();
+ rest.setMode(CapabilityStatement.RestfulCapabilityMode.CLIENT);
+ rest.getSecurity()
+ .addExtension()
+ .setUrl("http://foo")
+ .setValue(new StringType("bar"));
+
+ cs.getVersionElement().addExtension()
+ .setUrl("http://goo")
+ .setValue(new StringType("ber"));
+
+ String encoded = ourCtx.newXmlParser().setSummaryMode(true).setPrettyPrint(true).setPrettyPrint(true).encodeResourceToString(cs);
+ ourLog.info(encoded);
+
+ assertThat(encoded, Matchers.containsString("http://foo"));
+ assertThat(encoded, Matchers.containsString("bar"));
+ assertThat(encoded, Matchers.containsString("http://goo"));
+ assertThat(encoded, Matchers.containsString("ber"));
+ }
+
+
@Test
public void testEncodeInvalidMetaTime() {
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 24ebecacdde..58ab5ee9b26 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -266,6 +266,10 @@
A new server interceptor hook called PROCESSING_COMPLETED has been added. This
hook is called by the server at the end of processing every request (success and failure).
+
+ The _summary]]> element was not always respected when encoding
+ JSON resources.
+
From 0729e38e6ec5e472a0e3c87062623358d323dcc6 Mon Sep 17 00:00:00 2001
From: Diederik Muylwyk
Date: Thu, 11 Jul 2019 16:52:19 -0400
Subject: [PATCH 03/10] Resolve "experimental implementation for storing
expanded ValueSets in terminology tables" (#1369)
* Added experimental implementation for storing expanded ValueSets in terminology tables.
* Minor tweak to log message for consistency.
* Another minor tweak to log message for consistency.
* Renamed test.
* Addressing review comments.
* Added migration tasks.
---
.../java/ca/uhn/fhir/util/ValidateUtil.java | 16 +-
.../ca/uhn/fhir/i18n/hapi-messages.properties | 3 +-
.../java/ca/uhn/fhir/jpa/dao/DaoConfig.java | 32 ++++
.../fhir/jpa/dao/data/ITermCodeSystemDao.java | 2 +-
.../jpa/dao/data/ITermValueSetCodeDao.java | 35 ++++
.../fhir/jpa/dao/data/ITermValueSetDao.java | 43 +++++
.../dstu3/FhirResourceDaoValueSetDstu3.java | 34 +++-
.../dao/expunge/ExpungeEverythingService.java | 2 +
.../jpa/dao/r4/FhirResourceDaoValueSetR4.java | 62 +++++--
.../uhn/fhir/jpa/entity/TermCodeSystem.java | 28 ++-
.../jpa/entity/TermCodeSystemVersion.java | 19 +-
.../ca/uhn/fhir/jpa/entity/TermConcept.java | 77 ++++----
.../jpa/entity/TermConceptDesignation.java | 34 +++-
.../uhn/fhir/jpa/entity/TermConceptMap.java | 47 +++--
.../fhir/jpa/entity/TermConceptMapGroup.java | 47 +++--
.../entity/TermConceptMapGroupElement.java | 35 ++--
.../TermConceptMapGroupElementTarget.java | 39 ++--
.../entity/TermConceptParentChildLink.java | 26 +--
.../fhir/jpa/entity/TermConceptProperty.java | 43 +++--
.../ca/uhn/fhir/jpa/entity/TermValueSet.java | 144 +++++++++++++++
.../uhn/fhir/jpa/entity/TermValueSetCode.java | 172 ++++++++++++++++++
.../jpa/term/BaseHapiTerminologySvcImpl.java | 102 ++++++++++-
.../fhir/jpa/term/IHapiTerminologySvc.java | 4 +
.../FhirResourceDaoDstu3TerminologyTest.java | 49 ++---
.../ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java | 8 +
.../r4/FhirResourceDaoR4TerminologyTest.java | 2 +-
.../dao/r4/FhirResourceDaoR4ValueSetTest.java | 30 +--
.../jpa/term/TerminologySvcImplDstu3Test.java | 2 +-
.../jpa/term/TerminologySvcImplR4Test.java | 126 ++++++++++++-
.../tasks/HapiFhirJpaMigrationTasks.java | 35 ++++
30 files changed, 1080 insertions(+), 218 deletions(-)
create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetCodeDao.java
create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetDao.java
create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSet.java
create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java
index 6b5df86e696..8d234d690bb 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ValidateUtil.java
@@ -23,7 +23,7 @@ package ca.uhn.fhir.util;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
-import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.*;
public class ValidateUtil {
@@ -37,7 +37,7 @@ public class ValidateUtil {
}
/**
- * Throws {@link IllegalArgumentException} if theValue is <= theMinimum
+ * Throws {@link IllegalArgumentException} if theValue is < theMinimum
*/
public static void isGreaterThanOrEqualTo(long theValue, long theMinimum, String theMessage) {
if (theValue < theMinimum) {
@@ -45,6 +45,12 @@ public class ValidateUtil {
}
}
+ public static void isNotBlankOrThrowIllegalArgument(String theString, String theMessage) {
+ if (isBlank(theString)) {
+ throw new IllegalArgumentException(theMessage);
+ }
+ }
+
public static void isNotBlankOrThrowInvalidRequest(String theString, String theMessage) {
if (isBlank(theString)) {
throw new InvalidRequestException(theMessage);
@@ -57,6 +63,12 @@ public class ValidateUtil {
}
}
+ public static void isNotTooLongOrThrowIllegalArgument(String theString, int theMaxLength, String theMessage) {
+ if (length(theString) > theMaxLength) {
+ throw new IllegalArgumentException(theMessage);
+ }
+ }
+
public static void isTrueOrThrowInvalidRequest(boolean theSuccess, String theMessage) {
if (theSuccess == false) {
throw new InvalidRequestException(theMessage);
diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
index 5838eb9baf1..45d5426bda2 100644
--- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
+++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
@@ -115,8 +115,9 @@ ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor.noParam=Note that cascadi
ca.uhn.fhir.jpa.provider.BaseJpaProvider.cantCombintAtAndSince=Unable to combine _at and _since parameters for history operation
+ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemUrl=Can not create multiple CodeSystem resources with CodeSystem.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1}
-ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemUri=Can not create multiple code systems with URI "{0}", already have one with resource ID: {1}
+ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateValueSetUrl=Can not create multiple ValueSet resources with ValueSet.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
index 1a149a9134e..d8df260f116 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
@@ -145,6 +145,10 @@ public class DaoConfig {
private boolean myEnableInMemorySubscriptionMatching = true;
private boolean myEnforceReferenceTargetTypes = true;
private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC;
+ /**
+ * EXPERIMENTAL - Do not use in production! Do not change default of {@code false}!
+ */
+ private boolean myPreExpandValueSetsExperimental = false;
/**
* Constructor
@@ -1600,6 +1604,34 @@ public class DaoConfig {
myModelConfig.setWebsocketContextPath(theWebsocketContextPath);
}
+ /**
+ * EXPERIMENTAL - Do not use in production!
+ *
+ * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
+ * future optimization of the $expand operation on large ValueSets.
+ *
+ *
+ * The default value for this setting is {@code false}.
+ *
+ */
+ public boolean isPreExpandValueSetsExperimental() {
+ return myPreExpandValueSetsExperimental;
+ }
+
+ /**
+ * EXPERIMENTAL - Do not use in production!
+ *
+ * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
+ * future optimization of the $expand operation on large ValueSets.
+ *
+ *
+ * The default value for this setting is {@code false}.
+ *
+ */
+ public void setPreExpandValueSetsExperimental(boolean thePreExpandValueSetsExperimental) {
+ myPreExpandValueSetsExperimental = thePreExpandValueSetsExperimental;
+ }
+
public enum IndexEnabledEnum {
ENABLED,
DISABLED
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java
index 5fe695bc06c..3a672f8a312 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermCodeSystemDao.java
@@ -34,7 +34,7 @@ public interface ITermCodeSystemDao extends JpaRepository
TermCodeSystem findByCodeSystemUri(@Param("code_system_uri") String theCodeSystemUri);
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myResourcePid = :resource_pid")
- TermCodeSystem findByResourcePid(@Param("resource_pid") Long theReourcePid);
+ TermCodeSystem findByResourcePid(@Param("resource_pid") Long theResourcePid);
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myCurrentVersion.myId = :csv_pid")
Optional findWithCodeSystemVersionAsCurrentVersion(@Param("csv_pid") Long theCodeSystemVersionPid);
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetCodeDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetCodeDao.java
new file mode 100644
index 00000000000..5702aceb846
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetCodeDao.java
@@ -0,0 +1,35 @@
+package ca.uhn.fhir.jpa.dao.data;
+
+/*
+ * #%L
+ * HAPI FHIR JPA Server
+ * %%
+ * Copyright (C) 2014 - 2019 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import ca.uhn.fhir.jpa.entity.TermValueSetCode;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface ITermValueSetCodeDao extends JpaRepository {
+
+ @Query("DELETE FROM TermValueSetCode vsc WHERE vsc.myValueSet.myId = :pid")
+ @Modifying
+ void deleteTermValueSetCodesByValueSetId(@Param("pid") Long theValueSetId);
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetDao.java
new file mode 100644
index 00000000000..087dcefe70e
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetDao.java
@@ -0,0 +1,43 @@
+package ca.uhn.fhir.jpa.dao.data;
+
+/*
+ * #%L
+ * HAPI FHIR JPA Server
+ * %%
+ * Copyright (C) 2014 - 2019 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import ca.uhn.fhir.jpa.entity.TermValueSet;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.Optional;
+
+public interface ITermValueSetDao extends JpaRepository {
+
+ @Query("DELETE FROM TermValueSet vs WHERE vs.myId = :pid")
+ @Modifying
+ void deleteTermValueSetById(@Param("pid") Long theId);
+
+ @Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
+ Optional findByResourcePid(@Param("resource_pid") Long theResourcePid);
+
+ @Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url")
+ Optional findByUrl(@Param("url") String theUrl);
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java
index 93116549405..2f83a634c66 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java
@@ -23,11 +23,15 @@ package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails;
+import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ElementUtil;
import org.apache.commons.codec.binary.StringUtils;
+import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
import org.hl7.fhir.dstu3.model.*;
@@ -37,6 +41,8 @@ import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
+import org.hl7.fhir.exceptions.FHIRException;
+import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger;
@@ -45,14 +51,18 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3 implements IFhirResourceDaoValueSet {
-
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoValueSetDstu3.class);
+
+ @Autowired
+ private IHapiTerminologySvc myHapiTerminologySvc;
+
@Autowired
@Qualifier("myJpaValidationSupportChainDstu3")
private IValidationSupport myValidationSupport;
@@ -295,4 +305,26 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3
// nothing
}
+ @Override
+ protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
+ boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
+ ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
+
+ if (myDaoConfig.isPreExpandValueSetsExperimental()) {
+ if (retVal.getDeleted() == null) {
+ try {
+ ValueSet valueSet = (ValueSet) theResource;
+ org.hl7.fhir.r4.model.ValueSet converted = VersionConvertor_30_40.convertValueSet(valueSet);
+ myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, converted);
+ } catch (FHIRException fe) {
+ throw new InternalErrorException(fe);
+ }
+ } else {
+ myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
+ }
+ }
+
+ return retVal;
+ }
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java
index b704bb0668e..feaf1a820a9 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ExpungeEverythingService.java
@@ -74,6 +74,8 @@ public class ExpungeEverythingService {
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceLink.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SearchResult.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SearchInclude.class));
+ counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermValueSetCode.class));
+ counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermValueSet.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptParentChildLink.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMapGroupElementTarget.class));
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMapGroupElement.class));
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java
index c1c685ceb00..68e78e778db 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java
@@ -20,34 +20,43 @@ package ca.uhn.fhir.jpa.dao.r4;
* #L%
*/
-import static org.apache.commons.lang3.StringUtils.isBlank;
-import static org.apache.commons.lang3.StringUtils.isNotBlank;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.commons.codec.binary.StringUtils;
-import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
-import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
-import org.hl7.fhir.r4.model.*;
-import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
-import org.hl7.fhir.r4.model.ValueSet.*;
-import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.hl7.fhir.instance.model.api.IPrimitiveType;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ElementUtil;
+import org.apache.commons.codec.binary.StringUtils;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
+import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
+import org.hl7.fhir.r4.model.*;
+import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
+import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
+import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
+import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
+import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
+import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 implements IFhirResourceDaoValueSet {
+ @Autowired
+ private IHapiTerminologySvc myHapiTerminologySvc;
+
@Autowired
@Qualifier("myJpaValidationSupportChainR4")
private IValidationSupport myValidationSupport;
@@ -296,4 +305,21 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 imple
// nothing
}
+ @Override
+ protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
+ boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
+ ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
+
+ if (myDaoConfig.isPreExpandValueSetsExperimental()) {
+ if (retVal.getDeleted() == null) {
+ ValueSet valueSet = (ValueSet) theResource;
+ myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, valueSet);
+ } else {
+ myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
+ }
+ }
+
+ return retVal;
+ }
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java
index fd23f3f4065..6d468b49ae6 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystem.java
@@ -21,13 +21,16 @@ package ca.uhn.fhir.jpa.entity;
*/
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
//@formatter:off
@Table(name = "TRM_CODESYSTEM", uniqueConstraints = {
@@ -37,9 +40,11 @@ import static org.apache.commons.lang3.StringUtils.left;
//@formatter:on
public class TermCodeSystem implements Serializable {
private static final long serialVersionUID = 1L;
- public static final int CS_NAME_LENGTH = 200;
- @Column(name = "CODE_SYSTEM_URI", nullable = false)
+ private static final int MAX_NAME_LENGTH = 200;
+ static final int MAX_URL_LENGTH = 200;
+
+ @Column(name = "CODE_SYSTEM_URI", nullable = false, length = MAX_URL_LENGTH)
private String myCodeSystemUri;
@OneToOne()
@@ -55,7 +60,7 @@ public class TermCodeSystem implements Serializable {
private ResourceTable myResource;
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourcePid;
- @Column(name = "CS_NAME", nullable = true)
+ @Column(name = "CS_NAME", nullable = true, length = MAX_NAME_LENGTH)
private String myName;
public String getCodeSystemUri() {
@@ -66,16 +71,21 @@ public class TermCodeSystem implements Serializable {
return myName;
}
- public void setCodeSystemUri(String theCodeSystemUri) {
+ public TermCodeSystem setCodeSystemUri(@Nonnull String theCodeSystemUri) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCodeSystemUri, "theCodeSystemUri must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCodeSystemUri, MAX_URL_LENGTH,
+ "URI exceeds maximum length (" + MAX_URL_LENGTH + "): " + length(theCodeSystemUri));
myCodeSystemUri = theCodeSystemUri;
+ return this;
}
public TermCodeSystemVersion getCurrentVersion() {
return myCurrentVersion;
}
- public void setCurrentVersion(TermCodeSystemVersion theCurrentVersion) {
+ public TermCodeSystem setCurrentVersion(TermCodeSystemVersion theCurrentVersion) {
myCurrentVersion = theCurrentVersion;
+ return this;
}
public Long getPid() {
@@ -86,12 +96,14 @@ public class TermCodeSystem implements Serializable {
return myResource;
}
- public void setName(String theName) {
- myName = left(theName, CS_NAME_LENGTH);
+ public TermCodeSystem setName(String theName) {
+ myName = left(theName, MAX_NAME_LENGTH);
+ return this;
}
- public void setResource(ResourceTable theResource) {
+ public TermCodeSystem setResource(ResourceTable theResource) {
myResource = theResource;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java
index 2bd272cb6a5..969710901ea 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermCodeSystemVersion.java
@@ -22,12 +22,15 @@ package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.util.CoverageIgnore;
+import ca.uhn.fhir.util.ValidateUtil;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import static org.apache.commons.lang3.StringUtils.length;
+
//@formatter:off
@Table(name = "TRM_CODESYSTEM_VER"
// Note, we used to have a constraint named IDX_CSV_RESOURCEPID_AND_VER (don't reuse this)
@@ -37,6 +40,8 @@ import java.util.Collection;
public class TermCodeSystemVersion implements Serializable {
private static final long serialVersionUID = 1L;
+ static final int MAX_VERSION_LENGTH = 200;
+
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myCodeSystem")
private Collection myConcepts;
@@ -50,7 +55,7 @@ public class TermCodeSystemVersion implements Serializable {
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_CODESYSVER_RES_ID"))
private ResourceTable myResource;
- @Column(name = "CS_VERSION_ID", nullable = true, updatable = false)
+ @Column(name = "CS_VERSION_ID", nullable = true, updatable = false, length = MAX_VERSION_LENGTH)
private String myCodeSystemVersionId;
/**
* This was added in HAPI FHIR 3.3.0 and is nullable just to avoid migration
@@ -104,16 +109,21 @@ public class TermCodeSystemVersion implements Serializable {
return myCodeSystem;
}
- public void setCodeSystem(TermCodeSystem theCodeSystem) {
+ public TermCodeSystemVersion setCodeSystem(TermCodeSystem theCodeSystem) {
myCodeSystem = theCodeSystem;
+ return this;
}
public String getCodeSystemVersionId() {
return myCodeSystemVersionId;
}
- public void setCodeSystemVersionId(String theCodeSystemVersionId) {
+ public TermCodeSystemVersion setCodeSystemVersionId(String theCodeSystemVersionId) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(
+ theCodeSystemVersionId, MAX_VERSION_LENGTH,
+ "Version ID exceeds maximum length (" + MAX_VERSION_LENGTH + "): " + length(theCodeSystemVersionId));
myCodeSystemVersionId = theCodeSystemVersionId;
+ return this;
}
public Collection getConcepts() {
@@ -131,8 +141,9 @@ public class TermCodeSystemVersion implements Serializable {
return myResource;
}
- public void setResource(ResourceTable theResource) {
+ public TermCodeSystemVersion setResource(ResourceTable theResource) {
myResource = theResource;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java
index bfe8ee61f53..3a3158cc4bc 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java
@@ -1,25 +1,5 @@
package ca.uhn.fhir.jpa.entity;
-import ca.uhn.fhir.context.support.IContextValidationSupport;
-import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
-import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
-import ca.uhn.fhir.util.ValidateUtil;
-import org.apache.commons.lang3.Validate;
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import org.hibernate.search.annotations.*;
-import org.hl7.fhir.r4.model.Coding;
-
-import javax.annotation.Nonnull;
-import javax.persistence.*;
-import javax.persistence.Index;
-import java.io.Serializable;
-import java.util.*;
-
-import static org.apache.commons.lang3.StringUtils.isNotBlank;
-
/*
* #%L
* HAPI FHIR JPA Server
@@ -40,6 +20,27 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* #L%
*/
+import ca.uhn.fhir.context.support.IContextValidationSupport;
+import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
+import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
+import ca.uhn.fhir.util.ValidateUtil;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.hibernate.search.annotations.*;
+import org.hl7.fhir.r4.model.Coding;
+
+import javax.annotation.Nonnull;
+import javax.persistence.Index;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.*;
+
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Indexed(interceptor = DeferConceptIndexingInterceptor.class)
@Table(name = "TRM_CONCEPT", uniqueConstraints = {
@@ -49,16 +50,17 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Index(name = "IDX_CONCEPT_UPDATED", columnList = "CONCEPT_UPDATED")
})
public class TermConcept implements Serializable {
- public static final int CODE_LENGTH = 500;
- protected static final int MAX_DESC_LENGTH = 400;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermConcept.class);
private static final long serialVersionUID = 1L;
+ static final int MAX_CODE_LENGTH = 500;
+ static final int MAX_DESC_LENGTH = 400;
+
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myParent", cascade = {})
private Collection myChildren;
- @Column(name = "CODE", length = CODE_LENGTH, nullable = false)
+ @Column(name = "CODE", nullable = false, length = MAX_CODE_LENGTH)
@Fields({@Field(name = "myCode", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "exactAnalyzer")),})
private String myCode;
@Temporal(TemporalType.TIMESTAMP)
@@ -70,7 +72,7 @@ public class TermConcept implements Serializable {
@Column(name = "CODESYSTEM_PID", insertable = false, updatable = false)
@Fields({@Field(name = "myCodeSystemVersionPid")})
private long myCodeSystemVersionPid;
- @Column(name = "DISPLAY", length = MAX_DESC_LENGTH, nullable = true)
+ @Column(name = "DISPLAY", nullable = true, length = MAX_DESC_LENGTH)
@Fields({
@Field(name = "myDisplay", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
@Field(name = "myDisplayEdgeNGram", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteEdgeAnalyzer")),
@@ -187,20 +189,24 @@ public class TermConcept implements Serializable {
return myCode;
}
- public void setCode(String theCode) {
- ValidateUtil.isNotBlankOrThrowInvalidRequest(theCode, "Code must not be null or empty");
+ public TermConcept setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + MAX_CODE_LENGTH + "): " + length(theCode));
myCode = theCode;
+ return this;
}
public TermCodeSystemVersion getCodeSystemVersion() {
return myCodeSystem;
}
- public void setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
+ public TermConcept setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
myCodeSystem = theCodeSystemVersion;
if (theCodeSystemVersion.getPid() != null) {
myCodeSystemVersionPid = theCodeSystemVersion.getPid();
}
+ return this;
}
public List getCodingProperties(String thePropertyName) {
@@ -231,10 +237,7 @@ public class TermConcept implements Serializable {
}
public TermConcept setDisplay(String theDisplay) {
- myDisplay = theDisplay;
- if (isNotBlank(theDisplay) && theDisplay.length() > MAX_DESC_LENGTH) {
- myDisplay = myDisplay.substring(0, MAX_DESC_LENGTH);
- }
+ myDisplay = left(theDisplay, MAX_DESC_LENGTH);
return this;
}
@@ -246,8 +249,9 @@ public class TermConcept implements Serializable {
return myIndexStatus;
}
- public void setIndexStatus(Long theIndexStatus) {
+ public TermConcept setIndexStatus(Long theIndexStatus) {
myIndexStatus = theIndexStatus;
+ return this;
}
public String getParentPidsAsString() {
@@ -272,8 +276,9 @@ public class TermConcept implements Serializable {
return mySequence;
}
- public void setSequence(Integer theSequence) {
+ public TermConcept setSequence(Integer theSequence) {
mySequence = theSequence;
+ return this;
}
public List getStringProperties(String thePropertyName) {
@@ -300,8 +305,9 @@ public class TermConcept implements Serializable {
return myUpdated;
}
- public void setUpdated(Date theUpdated) {
+ public TermConcept setUpdated(Date theUpdated) {
myUpdated = theUpdated;
+ return this;
}
@Override
@@ -355,8 +361,9 @@ public class TermConcept implements Serializable {
myParentPids = b.toString();
}
- public void setParentPids(String theParentPids) {
+ public TermConcept setParentPids(String theParentPids) {
myParentPids = theParentPids;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java
index 9741d4377b4..4aeea98ccae 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptDesignation.java
@@ -20,16 +20,24 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.util.ValidateUtil;
+
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_DESIG", uniqueConstraints = {
}, indexes = {
})
public class TermConceptDesignation implements Serializable {
-
private static final long serialVersionUID = 1L;
+
+ private static final int MAX_LENGTH = 500;
+
@ManyToOne
@JoinColumn(name = "CONCEPT_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTDESIG_CONCEPT"))
private TermConcept myConcept;
@@ -38,15 +46,15 @@ public class TermConceptDesignation implements Serializable {
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_DESIG_PID")
@Column(name = "PID")
private Long myId;
- @Column(name = "LANG", length = 500, nullable = true)
+ @Column(name = "LANG", nullable = true, length = MAX_LENGTH)
private String myLanguage;
- @Column(name = "USE_SYSTEM", length = 500, nullable = true)
+ @Column(name = "USE_SYSTEM", nullable = true, length = MAX_LENGTH)
private String myUseSystem;
- @Column(name = "USE_CODE", length = 500, nullable = true)
+ @Column(name = "USE_CODE", nullable = true, length = MAX_LENGTH)
private String myUseCode;
- @Column(name = "USE_DISPLAY", length = 500, nullable = true)
+ @Column(name = "USE_DISPLAY", nullable = true, length = MAX_LENGTH)
private String myUseDisplay;
- @Column(name = "VAL", length = 500, nullable = false)
+ @Column(name = "VAL", nullable = false, length = MAX_LENGTH)
private String myValue;
/**
* TODO: Make this non-null
@@ -62,6 +70,8 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setLanguage(String theLanguage) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theLanguage, MAX_LENGTH,
+ "Language exceeds maximum length (" + MAX_LENGTH + "): " + length(theLanguage));
myLanguage = theLanguage;
return this;
}
@@ -71,6 +81,8 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setUseCode(String theUseCode) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseCode, MAX_LENGTH,
+ "Use code exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseCode));
myUseCode = theUseCode;
return this;
}
@@ -80,7 +92,7 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setUseDisplay(String theUseDisplay) {
- myUseDisplay = theUseDisplay;
+ myUseDisplay = left(theUseDisplay, MAX_LENGTH);
return this;
}
@@ -89,6 +101,9 @@ public class TermConceptDesignation implements Serializable {
}
public TermConceptDesignation setUseSystem(String theUseSystem) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUseSystem, MAX_LENGTH,
+ "Use system exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseSystem));
+
myUseSystem = theUseSystem;
return this;
}
@@ -97,7 +112,10 @@ public class TermConceptDesignation implements Serializable {
return myValue;
}
- public TermConceptDesignation setValue(String theValue) {
+ public TermConceptDesignation setValue(@Nonnull String theValue) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theValue, "theValue must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theValue, MAX_LENGTH,
+ "Value exceeds maximum length (" + MAX_LENGTH + "): " + length(theValue));
myValue = theValue;
return this;
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java
index fd67f26716c..24e1dda2797 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMap.java
@@ -21,19 +21,27 @@ package ca.uhn.fhir.jpa.entity;
*/
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP", uniqueConstraints = {
@UniqueConstraint(name = "IDX_CONCEPT_MAP_URL", columnNames = {"URL"})
})
public class TermConceptMap implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ static final int MAX_URL_LENGTH = 200;
+
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_PID", sequenceName = "SEQ_CONCEPT_MAP_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_PID")
@@ -47,13 +55,13 @@ public class TermConceptMap implements Serializable {
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourcePid;
- @Column(name = "SOURCE_URL", nullable = true, length = 200)
+ @Column(name = "SOURCE_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String mySource;
- @Column(name = "TARGET_URL", nullable = true, length = 200)
+ @Column(name = "TARGET_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myTarget;
- @Column(name = "URL", length = 200, nullable = false)
+ @Column(name = "URL", nullable = false, length = MAX_URL_LENGTH)
private String myUrl;
@OneToMany(mappedBy = "myConceptMap")
@@ -75,47 +83,58 @@ public class TermConceptMap implements Serializable {
return myResource;
}
- public void setResource(ResourceTable resource) {
- myResource = resource;
+ public TermConceptMap setResource(ResourceTable theResource) {
+ myResource = theResource;
+ return this;
}
public Long getResourcePid() {
return myResourcePid;
}
- public void setResourcePid(Long resourcePid) {
- myResourcePid = resourcePid;
+ public TermConceptMap setResourcePid(Long theResourcePid) {
+ myResourcePid = theResourcePid;
+ return this;
}
public String getSource() {
return mySource;
}
- public void setSource(String source) {
- mySource = source;
+ public TermConceptMap setSource(String theSource) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSource, TermValueSet.MAX_URL_LENGTH,
+ "Source exceeds maximum length (" + TermValueSet.MAX_URL_LENGTH + "): " + length(theSource));
+ mySource = theSource;
+ return this;
}
public String getTarget() {
return myTarget;
}
- public void setTarget(String target) {
- myTarget = target;
+ public TermConceptMap setTarget(String theTarget) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theTarget, TermValueSet.MAX_URL_LENGTH,
+ "Target exceeds maximum length (" + TermValueSet.MAX_URL_LENGTH + "): " + length(theTarget));
+ myTarget = theTarget;
+ return this;
}
public String getUrl() {
return myUrl;
}
- public void setUrl(String theUrl) {
+ public TermConceptMap setUrl(@Nonnull String theUrl) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theUrl, "theUrl must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUrl, MAX_URL_LENGTH,
+ "URL exceeds maximum length (" + MAX_URL_LENGTH + "): " + length(theUrl));
myUrl = theUrl;
+ return this;
}
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
- .append("myResource", myResource.toString())
.append(myResource != null ? ("myResource=" + myResource.toString()) : ("myResource=(null)"))
.append("myResourcePid", myResourcePid)
.append("mySource", mySource)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java
index 72d23359a0b..d11ae915f46 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroup.java
@@ -20,17 +20,23 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP_GROUP")
public class TermConceptMapGroup implements Serializable {
+ private static final long serialVersionUID = 1L;
+
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_GROUP_PID", sequenceName = "SEQ_CONCEPT_MAP_GROUP_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_GROUP_PID")
@@ -41,36 +47,37 @@ public class TermConceptMapGroup implements Serializable {
@JoinColumn(name = "CONCEPT_MAP_PID", nullable = false, referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_TCMGROUP_CONCEPTMAP"))
private TermConceptMap myConceptMap;
- @Column(name = "SOURCE_URL", nullable = false, length = 200)
+ @Column(name = "SOURCE_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySource;
- @Column(name = "SOURCE_VERSION", length = 100)
+ @Column(name = "SOURCE_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String mySourceVersion;
- @Column(name = "TARGET_URL", nullable = false, length = 200)
+ @Column(name = "TARGET_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
private String myTarget;
- @Column(name = "TARGET_VERSION", length = 100)
+ @Column(name = "TARGET_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String myTargetVersion;
@OneToMany(mappedBy = "myConceptMapGroup")
private List myConceptMapGroupElements;
- @Column(name= "CONCEPT_MAP_URL", length = 200, nullable = true)
+ @Column(name= "CONCEPT_MAP_URL", nullable = true, length = TermConceptMap.MAX_URL_LENGTH)
private String myConceptMapUrl;
- @Column(name= "SOURCE_VS", length = 200, nullable = true)
+ @Column(name= "SOURCE_VS", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String mySourceValueSet;
- @Column(name= "TARGET_VS", length = 200, nullable = true)
+ @Column(name= "TARGET_VS", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myTargetValueSet;
public TermConceptMap getConceptMap() {
return myConceptMap;
}
- public void setConceptMap(TermConceptMap theTermConceptMap) {
+ public TermConceptMapGroup setConceptMap(TermConceptMap theTermConceptMap) {
myConceptMap = theTermConceptMap;
+ return this;
}
public List getConceptMapGroupElements() {
@@ -96,8 +103,12 @@ public class TermConceptMapGroup implements Serializable {
return mySource;
}
- public void setSource(String theSource) {
+ public TermConceptMapGroup setSource(@Nonnull String theSource) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theSource, "theSource must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSource, TermCodeSystem.MAX_URL_LENGTH,
+ "Source exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSource));
this.mySource = theSource;
+ return this;
}
public String getSourceValueSet() {
@@ -111,16 +122,23 @@ public class TermConceptMapGroup implements Serializable {
return mySourceVersion;
}
- public void setSourceVersion(String theSourceVersion) {
+ public TermConceptMapGroup setSourceVersion(String theSourceVersion) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSourceVersion, TermCodeSystemVersion.MAX_VERSION_LENGTH,
+ "Source version ID exceeds maximum length (" + TermCodeSystemVersion.MAX_VERSION_LENGTH + "): " + length(theSourceVersion));
mySourceVersion = theSourceVersion;
+ return this;
}
public String getTarget() {
return myTarget;
}
- public void setTarget(String theTarget) {
+ public TermConceptMapGroup setTarget(@Nonnull String theTarget) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theTarget, "theTarget must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theTarget, TermCodeSystem.MAX_URL_LENGTH,
+ "Target exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theTarget));
this.myTarget = theTarget;
+ return this;
}
public String getTargetValueSet() {
@@ -134,13 +152,16 @@ public class TermConceptMapGroup implements Serializable {
return myTargetVersion;
}
- public void setTargetVersion(String theTargetVersion) {
+ public TermConceptMapGroup setTargetVersion(String theTargetVersion) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theTargetVersion, TermCodeSystemVersion.MAX_VERSION_LENGTH,
+ "Target version ID exceeds maximum length (" + TermCodeSystemVersion.MAX_VERSION_LENGTH + "): " + length(theTargetVersion));
myTargetVersion = theTargetVersion;
+ return this;
}
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
.append(myConceptMap != null ? ("myConceptMap - id=" + myConceptMap.getId()) : ("myConceptMap=(null)"))
.append("mySource", mySource)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java
index d36689129ae..f182b16165e 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElement.java
@@ -20,22 +20,28 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
-import org.apache.commons.lang3.Validate;
+import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP_GRP_ELEMENT", indexes = {
@Index(name = "IDX_CNCPT_MAP_GRP_CD", columnList = "SOURCE_CODE")
})
public class TermConceptMapGroupElement implements Serializable {
+ private static final long serialVersionUID = 1L;
+
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_GRP_ELM_PID", sequenceName = "SEQ_CONCEPT_MAP_GRP_ELM_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_GRP_ELM_PID")
@@ -46,7 +52,7 @@ public class TermConceptMapGroupElement implements Serializable {
@JoinColumn(name = "CONCEPT_MAP_GROUP_PID", nullable = false, referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_TCMGELEMENT_GROUP"))
private TermConceptMapGroup myConceptMapGroup;
- @Column(name = "SOURCE_CODE", nullable = false, length = TermConcept.CODE_LENGTH)
+ @Column(name = "SOURCE_CODE", nullable = false, length = TermConcept.MAX_CODE_LENGTH)
private String myCode;
@Column(name = "SOURCE_DISPLAY", length = TermConcept.MAX_DESC_LENGTH)
@@ -55,33 +61,37 @@ public class TermConceptMapGroupElement implements Serializable {
@OneToMany(mappedBy = "myConceptMapGroupElement")
private List myConceptMapGroupElementTargets;
- @Column(name = "CONCEPT_MAP_URL", length = 200)
+ @Column(name = "CONCEPT_MAP_URL", nullable = true, length = TermConceptMap.MAX_URL_LENGTH)
private String myConceptMapUrl;
- @Column(name = "SYSTEM_URL", length = 200)
+ @Column(name = "SYSTEM_URL", nullable = true, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySystem;
- @Column(name = "SYSTEM_VERSION", length = 200)
+ @Column(name = "SYSTEM_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String mySystemVersion;
- @Column(name = "VALUESET_URL", length = 200)
+ @Column(name = "VALUESET_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myValueSet;
public String getCode() {
return myCode;
}
- public void setCode(String theCode) {
- Validate.notBlank(theCode, "theCode must not be blank");
+ public TermConceptMapGroupElement setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
myCode = theCode;
+ return this;
}
public TermConceptMapGroup getConceptMapGroup() {
return myConceptMapGroup;
}
- public void setConceptMapGroup(TermConceptMapGroup theTermConceptMapGroup) {
+ public TermConceptMapGroupElement setConceptMapGroup(TermConceptMapGroup theTermConceptMapGroup) {
myConceptMapGroup = theTermConceptMapGroup;
+ return this;
}
public List getConceptMapGroupElementTargets() {
@@ -103,8 +113,9 @@ public class TermConceptMapGroupElement implements Serializable {
return myDisplay;
}
- public void setDisplay(String theDisplay) {
- myDisplay = theDisplay;
+ public TermConceptMapGroupElement setDisplay(String theDisplay) {
+ myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH);
+ return this;
}
public Long getId() {
@@ -158,7 +169,7 @@ public class TermConceptMapGroupElement implements Serializable {
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
.append(myConceptMapGroup != null ? ("myConceptMapGroup - id=" + myConceptMapGroup.getId()) : ("myConceptMapGroup=(null)"))
.append("myCode", myCode)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java
index 754161ca0a9..d463f7dddfb 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptMapGroupElementTarget.java
@@ -20,20 +20,28 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_MAP_GRP_ELM_TGT", indexes = {
@Index(name = "IDX_CNCPT_MP_GRP_ELM_TGT_CD", columnList = "TARGET_CODE")
})
public class TermConceptMapGroupElementTarget implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ static final int MAX_EQUIVALENCE_LENGTH = 50;
+
@Id()
@SequenceGenerator(name = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID", sequenceName = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID")
@@ -44,31 +52,38 @@ public class TermConceptMapGroupElementTarget implements Serializable {
@JoinColumn(name = "CONCEPT_MAP_GRP_ELM_PID", nullable = false, referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_TCMGETARGET_ELEMENT"))
private TermConceptMapGroupElement myConceptMapGroupElement;
- @Column(name = "TARGET_CODE", nullable = false, length = TermConcept.CODE_LENGTH)
+ @Column(name = "TARGET_CODE", nullable = false, length = TermConcept.MAX_CODE_LENGTH)
private String myCode;
- @Column(name = "TARGET_DISPLAY", length = TermConcept.MAX_DESC_LENGTH)
+ @Column(name = "TARGET_DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH)
private String myDisplay;
@Enumerated(EnumType.STRING)
- @Column(name = "TARGET_EQUIVALENCE", length = 50)
+ @Column(name = "TARGET_EQUIVALENCE", nullable = true, length = MAX_EQUIVALENCE_LENGTH)
private ConceptMapEquivalence myEquivalence;
- @Column(name = "CONCEPT_MAP_URL", length = 200)
+ @Column(name = "CONCEPT_MAP_URL", nullable = true, length = TermConceptMap.MAX_URL_LENGTH)
private String myConceptMapUrl;
- @Column(name = "SYSTEM_URL", length = 200)
+
+ @Column(name = "SYSTEM_URL", nullable = true, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySystem;
- @Column(name = "SYSTEM_VERSION", length = 200)
+
+ @Column(name = "SYSTEM_VERSION", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
private String mySystemVersion;
- @Column(name = "VALUESET_URL", length = 200)
+
+ @Column(name = "VALUESET_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
private String myValueSet;
public String getCode() {
return myCode;
}
- public void setCode(String theCode) {
+ public TermConceptMapGroupElementTarget setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
myCode = theCode;
+ return this;
}
public TermConceptMapGroupElement getConceptMapGroupElement() {
@@ -90,16 +105,18 @@ public class TermConceptMapGroupElementTarget implements Serializable {
return myDisplay;
}
- public void setDisplay(String theDisplay) {
+ public TermConceptMapGroupElementTarget setDisplay(String theDisplay) {
myDisplay = theDisplay;
+ return this;
}
public ConceptMapEquivalence getEquivalence() {
return myEquivalence;
}
- public void setEquivalence(ConceptMapEquivalence theEquivalence) {
+ public TermConceptMapGroupElementTarget setEquivalence(ConceptMapEquivalence theEquivalence) {
myEquivalence = theEquivalence;
+ return this;
}
public Long getId() {
@@ -155,7 +172,7 @@ public class TermConceptMapGroupElementTarget implements Serializable {
@Override
public String toString() {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("myId", myId)
.append(myConceptMapGroupElement != null ? ("myConceptMapGroupElement - id=" + myConceptMapGroupElement.getId()) : ("myConceptMapGroupElement=(null)"))
.append("myCode", myCode)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java
index dfb380d605e..c7d38eed131 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptParentChildLink.java
@@ -20,21 +20,9 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import javax.persistence.*;
import java.io.Serializable;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.ForeignKey;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.SequenceGenerator;
-import javax.persistence.Table;
-
@Entity
@Table(name = "TRM_CONCEPT_PC_LINK")
public class TermConceptParentChildLink implements Serializable {
@@ -136,20 +124,24 @@ public class TermConceptParentChildLink implements Serializable {
return result;
}
- public void setChild(TermConcept theChild) {
+ public TermConceptParentChildLink setChild(TermConcept theChild) {
myChild = theChild;
+ return this;
}
- public void setCodeSystem(TermCodeSystemVersion theCodeSystem) {
+ public TermConceptParentChildLink setCodeSystem(TermCodeSystemVersion theCodeSystem) {
myCodeSystem = theCodeSystem;
+ return this;
}
- public void setParent(TermConcept theParent) {
+ public TermConceptParentChildLink setParent(TermConcept theParent) {
myParent = theParent;
+ return this;
}
- public void setRelationshipType(RelationshipTypeEnum theRelationshipType) {
+ public TermConceptParentChildLink setRelationshipType(RelationshipTypeEnum theRelationshipType) {
myRelationshipType = theRelationshipType;
+ return this;
}
public enum RelationshipTypeEnum {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java
index 517dc1b70f1..144fc1ae632 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java
@@ -20,21 +20,29 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.util.ValidateUtil;
+import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.validator.constraints.NotBlank;
+import javax.annotation.Nonnull;
import javax.persistence.*;
import java.io.Serializable;
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
@Entity
@Table(name = "TRM_CONCEPT_PROPERTY", uniqueConstraints = {
}, indexes = {
})
public class TermConceptProperty implements Serializable {
-
- static final int MAX_PROPTYPE_ENUM_LENGTH = 6;
private static final long serialVersionUID = 1L;
+
+ private static final int MAX_LENGTH = 500;
+ static final int MAX_PROPTYPE_ENUM_LENGTH = 6;
+
@ManyToOne
@JoinColumn(name = "CONCEPT_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTPROP_CONCEPT"))
private TermConcept myConcept;
@@ -51,22 +59,22 @@ public class TermConceptProperty implements Serializable {
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PROP_PID")
@Column(name = "PID")
private Long myId;
- @Column(name = "PROP_KEY", length = 500, nullable = false)
+ @Column(name = "PROP_KEY", nullable = false, length = MAX_LENGTH)
@NotBlank
private String myKey;
- @Column(name = "PROP_VAL", length = 500, nullable = true)
+ @Column(name = "PROP_VAL", nullable = true, length = MAX_LENGTH)
private String myValue;
- @Column(name = "PROP_TYPE", length = MAX_PROPTYPE_ENUM_LENGTH, nullable = false)
+ @Column(name = "PROP_TYPE", nullable = false, length = MAX_PROPTYPE_ENUM_LENGTH)
private TermConceptPropertyTypeEnum myType;
/**
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
- @Column(name = "PROP_CODESYSTEM", length = 500, nullable = true)
+ @Column(name = "PROP_CODESYSTEM", length = MAX_LENGTH, nullable = true)
private String myCodeSystem;
/**
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
- @Column(name = "PROP_DISPLAY", length = 500, nullable = true)
+ @Column(name = "PROP_DISPLAY", length = MAX_LENGTH, nullable = true)
private String myDisplay;
/**
@@ -80,6 +88,8 @@ public class TermConceptProperty implements Serializable {
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
public TermConceptProperty setCodeSystem(String theCodeSystem) {
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCodeSystem, MAX_LENGTH,
+ "Property code system exceeds maximum length (" + MAX_LENGTH + "): " + length(theCodeSystem));
myCodeSystem = theCodeSystem;
return this;
}
@@ -95,7 +105,7 @@ public class TermConceptProperty implements Serializable {
* Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
*/
public TermConceptProperty setDisplay(String theDisplay) {
- myDisplay = theDisplay;
+ myDisplay = left(theDisplay, MAX_LENGTH);
return this;
}
@@ -103,15 +113,20 @@ public class TermConceptProperty implements Serializable {
return myKey;
}
- public void setKey(String theKey) {
+ public TermConceptProperty setKey(@Nonnull String theKey) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theKey, "theKey must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theKey, MAX_LENGTH,
+ "Code exceeds maximum length (" + MAX_LENGTH + "): " + length(theKey));
myKey = theKey;
+ return this;
}
public TermConceptPropertyTypeEnum getType() {
return myType;
}
- public TermConceptProperty setType(TermConceptPropertyTypeEnum theType) {
+ public TermConceptProperty setType(@Nonnull TermConceptPropertyTypeEnum theType) {
+ Validate.notNull(theType);
myType = theType;
return this;
}
@@ -128,8 +143,9 @@ public class TermConceptProperty implements Serializable {
* This will contain the value for a {@link TermConceptPropertyTypeEnum#STRING string}
* property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
*/
- public void setValue(String theValue) {
- myValue = theValue;
+ public TermConceptProperty setValue(String theValue) {
+ myValue = left(theValue, MAX_LENGTH);
+ return this;
}
public TermConceptProperty setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
@@ -137,8 +153,9 @@ public class TermConceptProperty implements Serializable {
return this;
}
- public void setConcept(TermConcept theConcept) {
+ public TermConceptProperty setConcept(TermConcept theConcept) {
myConcept = theConcept;
+ return this;
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSet.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSet.java
new file mode 100644
index 00000000000..d53d6d07191
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSet.java
@@ -0,0 +1,144 @@
+package ca.uhn.fhir.jpa.entity;
+
+/*
+ * #%L
+ * HAPI FHIR JPA Server
+ * %%
+ * Copyright (C) 2014 - 2019 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.util.ValidateUtil;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.annotation.Nonnull;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
+@Table(name = "TRM_VALUESET", uniqueConstraints = {
+ @UniqueConstraint(name = "IDX_VALUESET_URL", columnNames = {"URL"})
+})
+@Entity()
+public class TermValueSet implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private static final int MAX_NAME_LENGTH = 200;
+ static final int MAX_URL_LENGTH = 200;
+
+ @Id()
+ @SequenceGenerator(name = "SEQ_VALUESET_PID", sequenceName = "SEQ_VALUESET_PID")
+ @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_PID")
+ @Column(name = "PID")
+ private Long myId;
+
+ @Column(name = "URL", nullable = false, length = MAX_URL_LENGTH)
+ private String myUrl;
+
+ @OneToOne()
+ @JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_TRMVALUESET_RES"))
+ private ResourceTable myResource;
+
+ @Column(name = "RES_ID", insertable = false, updatable = false)
+ private Long myResourcePid;
+
+ @Column(name = "NAME", nullable = true, length = MAX_NAME_LENGTH)
+ private String myName;
+
+ @OneToMany(mappedBy = "myValueSet")
+ private List myCodes;
+
+ public Long getId() {
+ return myId;
+ }
+
+ public String getUrl() {
+ return myUrl;
+ }
+
+ public TermValueSet setUrl(@Nonnull String theUrl) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theUrl, "theUrl must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theUrl, MAX_URL_LENGTH,
+ "URL exceeds maximum length (" + MAX_URL_LENGTH + "): " + length(theUrl));
+ myUrl = theUrl;
+ return this;
+ }
+
+ public ResourceTable getResource() {
+ return myResource;
+ }
+
+ public TermValueSet setResource(ResourceTable theResource) {
+ myResource = theResource;
+ return this;
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ public TermValueSet setName(String theName) {
+ myName = left(theName, MAX_NAME_LENGTH);
+ return this;
+ }
+
+ public List getCodes() {
+ if (myCodes == null) {
+ myCodes = new ArrayList<>();
+ }
+
+ return myCodes;
+ }
+
+ @Override
+ public boolean equals(Object theO) {
+ if (this == theO) return true;
+
+ if (!(theO instanceof TermValueSet)) return false;
+
+ TermValueSet that = (TermValueSet) theO;
+
+ return new EqualsBuilder()
+ .append(getUrl(), that.getUrl())
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(getUrl())
+ .toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("myId", myId)
+ .append("myUrl", myUrl)
+ .append(myResource != null ? ("myResource=" + myResource.toString()) : ("myResource=(null)"))
+ .append("myResourcePid", myResourcePid)
+ .append("myName", myName)
+ .append(myCodes != null ? ("myCodes - size=" + myCodes.size()) : ("myCodes=(null)"))
+ .toString();
+ }
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
new file mode 100644
index 00000000000..bbe0f518c35
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
@@ -0,0 +1,172 @@
+package ca.uhn.fhir.jpa.entity;
+
+/*
+ * #%L
+ * HAPI FHIR JPA Server
+ * %%
+ * Copyright (C) 2014 - 2019 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import ca.uhn.fhir.util.ValidateUtil;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.annotation.Nonnull;
+import javax.persistence.*;
+import java.io.Serializable;
+
+import static org.apache.commons.lang3.StringUtils.left;
+import static org.apache.commons.lang3.StringUtils.length;
+
+@Table(name = "TRM_VALUESET_CODE", indexes = {
+ @Index(name = "IDX_VALUESET_CODE_CS_CD", columnList = "SYSTEM, CODE")
+})
+@Entity()
+public class TermValueSetCode implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Id()
+ @SequenceGenerator(name = "SEQ_VALUESET_CODE_PID", sequenceName = "SEQ_VALUESET_CODE_PID")
+ @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_CODE_PID")
+ @Column(name = "PID")
+ private Long myId;
+
+ @ManyToOne()
+ @JoinColumn(name = "VALUESET_PID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_PID"))
+ private TermValueSet myValueSet;
+
+ @Transient
+ private String myValueSetUrl;
+
+ @Transient
+ private String myValueSetName;
+
+ @Column(name = "SYSTEM", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
+ private String mySystem;
+
+ @Column(name = "CODE", nullable = false, length = TermConcept.MAX_CODE_LENGTH)
+ private String myCode;
+
+ @Column(name = "DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH)
+ private String myDisplay;
+
+ public Long getId() {
+ return myId;
+ }
+
+ public TermValueSet getValueSet() {
+ return myValueSet;
+ }
+
+ public TermValueSetCode setValueSet(TermValueSet theValueSet) {
+ myValueSet = theValueSet;
+ return this;
+ }
+
+ public String getValueSetUrl() {
+ if (myValueSetUrl == null) {
+ myValueSetUrl = getValueSet().getUrl();
+ }
+
+ return myValueSetUrl;
+ }
+
+ public String getValueSetName() {
+ if (myValueSetName == null) {
+ myValueSetName = getValueSet().getName();
+ }
+
+ return myValueSetName;
+ }
+
+ public String getSystem() {
+ return mySystem;
+ }
+
+ public TermValueSetCode setSystem(@Nonnull String theSystem) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theSystem, "theSystem must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSystem, TermCodeSystem.MAX_URL_LENGTH,
+ "System exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSystem));
+
+ ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystem, "theSystem must not be null or empty");
+ if (theSystem.length() > TermCodeSystem.MAX_URL_LENGTH) {
+ throw new IllegalArgumentException();
+ }
+ mySystem = theSystem;
+ return this;
+ }
+
+ public String getCode() {
+ return myCode;
+ }
+
+ public TermValueSetCode setCode(@Nonnull String theCode) {
+ ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
+ ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
+ "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
+
+ myCode = theCode;
+ return this;
+ }
+
+ public String getDisplay() {
+ return myDisplay;
+ }
+
+ public TermValueSetCode setDisplay(String theDisplay) {
+ myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH);
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object theO) {
+ if (this == theO) return true;
+
+ if (!(theO instanceof TermValueSetCode)) return false;
+
+ TermValueSetCode that = (TermValueSetCode) theO;
+
+ return new EqualsBuilder()
+ .append(getValueSetUrl(), that.getValueSetUrl())
+ .append(getSystem(), that.getSystem())
+ .append(getCode(), that.getCode())
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(getValueSetUrl())
+ .append(getSystem())
+ .append(getCode())
+ .toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("myId", myId)
+ .append(myValueSet != null ? ("myValueSet - id=" + myValueSet.getId()) : ("myValueSet=(null)"))
+ .append("myValueSetUrl", this.getValueSetUrl())
+ .append("myValueSetName", this.getValueSetName())
+ .append("mySystem", mySystem)
+ .append("myCode", myCode)
+ .append("myDisplay", myDisplay)
+ .toString();
+ }
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java
index ba55a3712e9..165f1918d60 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java
@@ -119,6 +119,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
@Autowired
protected ITermConceptDesignationDao myConceptDesignationDao;
@Autowired
+ protected ITermValueSetDao myValueSetDao;
+ @Autowired
+ protected ITermValueSetCodeDao myValueSetCodeDao;
+ @Autowired
protected FhirContext myContext;
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
protected EntityManager myEntityManager;
@@ -388,6 +392,31 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
deleteConceptMap(theResourceTable);
}
+ public void deleteValueSet(ResourceTable theResourceTable) {
+ // Get existing entity so it can be deleted.
+ Optional optionalExistingTermValueSetById = myValueSetDao.findByResourcePid(theResourceTable.getId());
+
+ if (optionalExistingTermValueSetById.isPresent()) {
+ TermValueSet existingTermValueSet = optionalExistingTermValueSetById.get();
+
+ ourLog.info("Deleting existing TermValueSet {} and its children...", existingTermValueSet.getId());
+ myValueSetCodeDao.deleteTermValueSetCodesByValueSetId(existingTermValueSet.getId());
+ myValueSetDao.deleteTermValueSetById(existingTermValueSet.getId());
+ ourLog.info("Done deleting existing TermValueSet {} and its children.", existingTermValueSet.getId());
+
+ ourLog.info("Flushing...");
+ myValueSetCodeDao.flush();
+ myValueSetDao.flush();
+ ourLog.info("Done flushing.");
+ }
+ }
+
+ @Override
+ @Transactional
+ public void deleteValueSetAndChildren(ResourceTable theResourceTable) {
+ deleteValueSet(theResourceTable);
+ }
+
private void doDelete(String theDescriptor, Supplier> theLoader, Supplier theCounter, JpaRepository theDao) {
int count;
ourLog.info(" * Deleting {}", theDescriptor);
@@ -690,7 +719,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private void expandWithoutHibernateSearch(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) {
ourLog.trace("Hibernate search is not enabled");
- Validate.isTrue(theExpansionComponent.getParameter().isEmpty(), "Can not exapnd ValueSet with parameters - Hibernate Search is not enabled on this server.");
+ Validate.isTrue(theExpansionComponent.getParameter().isEmpty(), "Can not expand ValueSet with parameters - Hibernate Search is not enabled on this server.");
Validate.isTrue(theInclude.getFilter().isEmpty(), "Can not expand ValueSet with filters - Hibernate Search is not enabled on this server.");
Validate.isTrue(isNotBlank(theSystem), "Can not expand ValueSet without explicit system - Hibernate Search is not enabled on this server.");
@@ -1144,7 +1173,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
myCodeSystemDao.save(codeSystem);
} else {
if (!ObjectUtil.equals(codeSystem.getResource().getId(), theCodeSystemVersion.getResource().getId())) {
- String msg = myContext.getLocalizer().getMessage(BaseHapiTerminologySvcImpl.class, "cannotCreateDuplicateCodeSystemUri", theSystemUri,
+ String msg = myContext.getLocalizer().getMessage(BaseHapiTerminologySvcImpl.class, "cannotCreateDuplicateCodeSystemUrl", theSystemUri,
codeSystem.getResource().getIdDt().toUnqualifiedVersionless().getValue());
throw new UnprocessableEntityException(msg);
}
@@ -1310,7 +1339,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget);
if (codesSaved++ % 250 == 0) {
- ourLog.info("Have saved {} codes in conceptmap", codesSaved);
+ ourLog.info("Have saved {} codes in ConceptMap", codesSaved);
myConceptMapGroupElementTargetDao.flush();
}
}
@@ -1334,6 +1363,69 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
ourLog.info("Done storing TermConceptMap.");
}
+ @Override
+ @Transactional
+ public void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet) {
+ ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue());
+
+ ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
+ ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theValueSet.getUrl(), "ValueSet has no value for ValueSet.url");
+
+ TermValueSet termValueSet = new TermValueSet();
+ termValueSet.setResource(theResourceTable);
+ termValueSet.setUrl(theValueSet.getUrl());
+ termValueSet.setName(theValueSet.hasName() ? theValueSet.getName() : null);
+
+ // We delete old versions; we don't support versioned ValueSets.
+ deleteValueSet(theResourceTable);
+
+ /*
+ * Do the upload.
+ */
+ String url = termValueSet.getUrl();
+ Optional optionalExistingTermValueSetByUrl = myValueSetDao.findByUrl(url);
+ if (!optionalExistingTermValueSetByUrl.isPresent()) {
+ myValueSetDao.save(termValueSet);
+ int codesSaved = 0;
+
+ ValueSet expandedValueSet = expandValueSet(theValueSet);
+ if (expandedValueSet.hasExpansion()) {
+ if (expandedValueSet.getExpansion().hasTotal() && expandedValueSet.getExpansion().getTotal() > 0) {
+ TermValueSetCode code;
+ for (ValueSet.ValueSetExpansionContainsComponent contains : expandedValueSet.getExpansion().getContains()) {
+ ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getSystem(), "ValueSet contains a code with no system value");
+ ValidateUtil.isNotBlankOrThrowInvalidRequest(contains.getCode(), "ValueSet contains a code with no code value");
+
+ code = new TermValueSetCode();
+ code.setValueSet(termValueSet);
+ code.setSystem(contains.getSystem());
+ code.setCode(contains.getCode());
+ code.setDisplay(contains.hasDisplay() ? contains.getDisplay() : null);
+ myValueSetCodeDao.save(code);
+
+ if (codesSaved++ % 250 == 0) {
+ ourLog.info("Have pre-expanded {} codes in ValueSet", codesSaved);
+ myValueSetCodeDao.flush();
+ }
+ }
+ }
+ }
+
+ } else {
+ TermValueSet existingTermValueSet = optionalExistingTermValueSetByUrl.get();
+
+ String msg = myContext.getLocalizer().getMessage(
+ BaseHapiTerminologySvcImpl.class,
+ "cannotCreateDuplicateValueSetUrl",
+ url,
+ existingTermValueSet.getResource().getIdDt().toUnqualifiedVersionless().getValue());
+
+ throw new UnprocessableEntityException(msg);
+ }
+
+ ourLog.info("Done storing TermValueSet.");
+ }
+
@Override
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType theCodeA, IPrimitiveType theCodeB, IPrimitiveType theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB) {
VersionIndependentConcept conceptA = toConcept(theCodeA, theSystem, theCodingA);
@@ -1581,9 +1673,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
private int validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, ArrayList theConceptsStack,
IdentityHashMap theAllConcepts) {
- ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() != null, "CodesystemValue is null");
+ ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() != null, "CodeSystemVersion is null");
ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() == theCodeSystem, "CodeSystems are not equal");
- ValidateUtil.isNotBlankOrThrowInvalidRequest(theConcept.getCode(), "Codesystem contains a code with no code value");
+ ValidateUtil.isNotBlankOrThrowInvalidRequest(theConcept.getCode(), "CodeSystem contains a code with no code value");
if (theConceptsStack.contains(theConcept.getCode())) {
throw new InvalidRequestException("CodeSystem contains circular reference around code " + theConcept.getCode());
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java
index cc861e27f7f..4d50f75afb5 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java
@@ -81,8 +81,12 @@ public interface IHapiTerminologySvc {
void deleteConceptMapAndChildren(ResourceTable theResourceTable);
+ void deleteValueSetAndChildren(ResourceTable theResourceTable);
+
void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap);
+ void storeTermValueSetAndChildren(ResourceTable theResourceTable, ValueSet theValueSet);
+
boolean supportsSystem(String theCodeSystem);
List translate(TranslationRequest theTranslationRequest);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java
index b03e0b09148..64390e9a671 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java
@@ -1,31 +1,13 @@
package ca.uhn.fhir.jpa.dao.dstu3;
-import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.containsStringIgnoringCase;
-import static org.hamcrest.Matchers.empty;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-import java.util.*;
-
-import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
-import org.hl7.fhir.dstu3.model.*;
-import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceCategory;
-import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceClinicalStatus;
-import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
-import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
-import org.hl7.fhir.dstu3.model.ValueSet.*;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.junit.*;
-import org.springframework.beans.factory.annotation.Autowired;
-
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
-import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
-import ca.uhn.fhir.jpa.model.entity.*;
-import ca.uhn.fhir.jpa.entity.*;
+import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
+import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.param.TokenParam;
@@ -35,6 +17,25 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
+import org.hl7.fhir.dstu3.model.*;
+import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceCategory;
+import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceClinicalStatus;
+import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
+import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
+import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
+import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
+import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
+import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.junit.*;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
@@ -226,7 +227,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
myCodeSystemDao.create(codeSystem, mySrd);
fail();
} catch (UnprocessableEntityException e) {
- assertEquals("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
+ assertEquals("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java
index e3d27011253..877d0601247 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java
@@ -118,6 +118,10 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
@Qualifier("myCodeSystemDaoR4")
protected IFhirResourceDaoCodeSystem myCodeSystemDao;
@Autowired
+ protected ITermCodeSystemDao myTermCodeSystemDao;
+ @Autowired
+ protected ITermCodeSystemVersionDao myTermCodeSystemVersionDao;
+ @Autowired
@Qualifier("myCompartmentDefinitionDaoR4")
protected IFhirResourceDao myCompartmentDefinitionDao;
@Autowired
@@ -287,6 +291,10 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
@Qualifier("myValueSetDaoR4")
protected IFhirResourceDaoValueSet myValueSetDao;
@Autowired
+ protected ITermValueSetDao myTermValueSetDao;
+ @Autowired
+ protected ITermValueSetCodeDao myTermValueSetCodeDao;
+ @Autowired
protected ITermConceptMapDao myTermConceptMapDao;
@Autowired
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java
index 589f593c373..e362d462251 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java
@@ -222,7 +222,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
myCodeSystemDao.create(codeSystem, mySrd);
fail();
} catch (UnprocessableEntityException e) {
- assertEquals("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
+ assertEquals("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java
index 2a10ef2f9c6..cf3d7ce0bd6 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java
@@ -1,34 +1,20 @@
package ca.uhn.fhir.jpa.dao.r4;
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.stringContainsInOrder;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-
-import org.hl7.fhir.r4.model.CodeSystem;
-import org.hl7.fhir.r4.model.CodeType;
-import org.hl7.fhir.r4.model.CodeableConcept;
-import org.hl7.fhir.r4.model.Coding;
-import org.hl7.fhir.r4.model.IdType;
-import org.hl7.fhir.r4.model.Parameters;
-import org.hl7.fhir.r4.model.StringType;
-import org.hl7.fhir.r4.model.UriType;
-import org.hl7.fhir.r4.model.ValueSet;
+import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
+import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.r4.model.*;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
-import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
-import ca.uhn.fhir.util.TestUtil;
+import java.io.IOException;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
@@ -224,7 +210,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
@Test
- public void testValiedateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
+ public void testValidateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
IPrimitiveType display = null;
Coding coding = null;
CodeableConcept codeableConcept = null;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java
index e7006342458..3089835220d 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java
@@ -177,7 +177,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
fail();
} catch (UnprocessableEntityException e) {
- assertThat(e.getMessage(), containsString("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/"));
+ assertThat(e.getMessage(), containsString("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/"));
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java
index 785de25822c..e1ebe208e36 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java
@@ -2,17 +2,12 @@ package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
-import ca.uhn.fhir.jpa.entity.TermConceptMap;
-import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
-import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
-import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
+import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
-import org.hl7.fhir.r4.model.CanonicalType;
-import org.hl7.fhir.r4.model.ConceptMap;
+import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
-import org.hl7.fhir.r4.model.UriType;
import org.junit.*;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
@@ -21,6 +16,7 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
+import java.io.IOException;
import java.util.List;
import java.util.Optional;
@@ -31,6 +27,8 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@Rule
public final ExpectedException expectedException = ExpectedException.none();
private IIdType myConceptMapId;
+ private IIdType myExtensionalCsId;
+ private IIdType myExtensionalVsId;
@Before
public void before() {
@@ -40,6 +38,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
@After
public void after() {
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
+ myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
}
private void createAndPersistConceptMap() {
@@ -56,6 +55,39 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
});
}
+ private void loadAndPersistCodeSystemAndValueSet() throws IOException {
+ loadAndPersistCodeSystem();
+ loadAndPersistValueSet();
+ }
+
+ private void loadAndPersistCodeSystem() throws IOException {
+ CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
+ persistCodeSystem(codeSystem);
+ }
+
+ private void persistCodeSystem(CodeSystem theCodeSystem) {
+ new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
+ @Override
+ protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
+ myExtensionalCsId = myCodeSystemDao.create(theCodeSystem, mySrd).getId().toUnqualifiedVersionless();
+ }
+ });
+ }
+
+ private void loadAndPersistValueSet() throws IOException {
+ ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
+ persistValueSet(valueSet);
+ }
+
+ private void persistValueSet(ValueSet theValueSet) {
+ new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
+ @Override
+ protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
+ myExtensionalVsId = myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless();
+ }
+ });
+ }
+
@Test
public void testCreateConceptMapWithMissingSourceSystem() {
ConceptMap conceptMap = new ConceptMap();
@@ -137,6 +169,16 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
}
+ @Test
+ public void testDuplicateCodeSystemUrls() throws Exception {
+ loadAndPersistCodeSystem();
+
+ expectedException.expect(UnprocessableEntityException.class);
+ expectedException.expectMessage("Can not create multiple CodeSystem resources with CodeSystem.url \"http://acme.org\", already have one with resource ID: CodeSystem/" + myExtensionalCsId.getIdPart());
+
+ loadAndPersistCodeSystem();
+ }
+
@Test
public void testDuplicateConceptMapUrls() {
createAndPersistConceptMap();
@@ -147,6 +189,19 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
createAndPersistConceptMap();
}
+ @Test
+ public void testDuplicateValueSetUrls() throws Exception {
+ myDaoConfig.setPreExpandValueSetsExperimental(true);
+
+ // DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail.
+ loadAndPersistCodeSystemAndValueSet();
+
+ expectedException.expect(UnprocessableEntityException.class);
+ expectedException.expectMessage("Can not create multiple ValueSet resources with ValueSet.url \"http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2\", already have one with resource ID: ValueSet/" + myExtensionalVsId.getIdPart());
+
+ loadAndPersistValueSet();
+ }
+
@Test
public void testStoreTermConceptMapAndChildren() {
createAndPersistConceptMap();
@@ -325,6 +380,63 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
});
}
+ @Test
+ public void testStoreTermValueSetAndChildren() throws Exception {
+ myDaoConfig.setPreExpandValueSetsExperimental(true);
+
+ loadAndPersistCodeSystemAndValueSet();
+
+ CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
+ ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
+
+ ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
+ ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
+
+ new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
+ @Override
+ protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
+ Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong());
+ assertTrue(optionalValueSetByResourcePid.isPresent());
+
+ Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
+ assertTrue(optionalValueSetByUrl.isPresent());
+
+ TermValueSet valueSet = optionalValueSetByUrl.get();
+ assertSame(optionalValueSetByResourcePid.get(), valueSet);
+ ourLog.info("ValueSet:\n" + valueSet.toString());
+ assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", valueSet.getUrl());
+ assertEquals("Terminology Services Connectation #1 Extensional case #2", valueSet.getName());
+ assertEquals(codeSystem.getConcept().size(), valueSet.getCodes().size());
+
+ TermValueSetCode code = valueSet.getCodes().get(0);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("8450-9", code.getCode());
+ assertEquals("Systolic blood pressure--expiration", code.getDisplay());
+
+ code = valueSet.getCodes().get(1);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("11378-7", code.getCode());
+ assertEquals("Systolic blood pressure at First encounter", code.getDisplay());
+
+ // ...
+
+ code = valueSet.getCodes().get(22);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("8491-3", code.getCode());
+ assertEquals("Systolic blood pressure 1 hour minimum", code.getDisplay());
+
+ code = valueSet.getCodes().get(23);
+ ourLog.info("Code:\n" + code.toString());
+ assertEquals("http://acme.org", code.getSystem());
+ assertEquals("8492-1", code.getCode());
+ assertEquals("Systolic blood pressure 8 hour minimum", code.getDisplay());
+ }
+ });
+ }
+
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToMany() {
createAndPersistConceptMap();
diff --git a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java
index 852e9204c22..163c11a0626 100644
--- a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java
+++ b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java
@@ -75,6 +75,41 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
.renameColumn("mySystem", "SYSTEM_URL")
.renameColumn("mySystemVersion", "SYSTEM_VERSION")
.renameColumn("myValueSet", "VALUESET_URL");
+
+ // TermValueSet
+ version.startSectionWithMessage("Processing table: TRM_VALUESET");
+ version.addIdGenerator("SEQ_VALUESET_PID");
+ Builder.BuilderAddTableByColumns termValueSetTable = version.addTableByColumns("TRM_VALUESET", "PID");
+ termValueSetTable.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetTable.addColumn("URL").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+ termValueSetTable
+ .addIndex("IDX_VALUESET_URL")
+ .unique(true)
+ .withColumns("URL");
+ termValueSetTable.addColumn("RES_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetTable
+ .addForeignKey("FK_TRMVALUESET_RES")
+ .toColumn("RES_ID")
+ .references("HFJ_RESOURCE", "RES_ID");
+ termValueSetTable.addColumn("NAME").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+
+ // TermValueSetCode
+ version.startSectionWithMessage("Processing table: TRM_VALUESET_CODE");
+ version.addIdGenerator("SEQ_VALUESET_CODE_PID");
+ Builder.BuilderAddTableByColumns termValueSetCodeTable = version.addTableByColumns("TRM_VALUESET_CODE", "PID");
+ termValueSetCodeTable.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetCodeTable.addColumn("VALUESET_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
+ termValueSetCodeTable
+ .addForeignKey("FK_TRM_VALUESET_PID")
+ .toColumn("VALUESET_PID")
+ .references("TRM_VALUESET", "PID");
+ termValueSetCodeTable.addColumn("SYSTEM").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+ termValueSetCodeTable.addColumn("CODE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
+ termValueSetCodeTable
+ .addIndex("IDX_VALUESET_CODE_CS_CD")
+ .unique(false)
+ .withColumns("SYSTEM", "CODE");
+ termValueSetCodeTable.addColumn("DISPLAY").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING);
}
From 62e1b7e9eaaea087377a21d186c999186c1531d6 Mon Sep 17 00:00:00 2001
From: Diederik Muylwyk
Date: Thu, 11 Jul 2019 17:07:26 -0400
Subject: [PATCH 04/10] Fixing minor overlooked change from recent pull
request.
---
.../main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java | 6 ------
1 file changed, 6 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
index bbe0f518c35..88fc16f5b1f 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetCode.java
@@ -102,11 +102,6 @@ public class TermValueSetCode implements Serializable {
ValidateUtil.isNotBlankOrThrowIllegalArgument(theSystem, "theSystem must not be null or empty");
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theSystem, TermCodeSystem.MAX_URL_LENGTH,
"System exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSystem));
-
- ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystem, "theSystem must not be null or empty");
- if (theSystem.length() > TermCodeSystem.MAX_URL_LENGTH) {
- throw new IllegalArgumentException();
- }
mySystem = theSystem;
return this;
}
@@ -119,7 +114,6 @@ public class TermValueSetCode implements Serializable {
ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCode, TermConcept.MAX_CODE_LENGTH,
"Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
-
myCode = theCode;
return this;
}
From 642e62a56383d6009fbdc9ccc9b6cf9f8137be4b Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Thu, 11 Jul 2019 18:17:13 -0400
Subject: [PATCH 05/10] Improve toString method
---
.../java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java
index 62a8e14de6b..7d91f3dbc23 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/SearchParameterMap.java
@@ -446,7 +446,7 @@ public class SearchParameterMap implements Serializable {
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
if (isEmpty() == false) {
- b.append("params", super.toString());
+ b.append("params", mySearchParameterMap);
}
if (getIncludes().isEmpty() == false) {
b.append("includes", getIncludes());
From 1db019b6df951cf1bb49382a8238f4c3e4f0577f Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Thu, 11 Jul 2019 20:20:27 -0400
Subject: [PATCH 06/10] Test fix and try to get Travis building again
---
.../ca/uhn/fhir/interceptor/api/Pointcut.java | 35 ++
.../java/ca/uhn/fhir/parser/JsonParser.java | 13 +-
.../ca/uhn/fhir/jpa/dao/SearchBuilder.java | 43 +--
.../jpa/search/SearchCoordinatorSvcImpl.java | 8 +
.../ca/uhn/fhir/jpa/config/TestR4Config.java | 3 +-
...ResourceDaoDstu3UniqueSearchParamTest.java | 345 ------------------
...hirResourceDaoR4UniqueSearchParamTest.java | 210 +++++++++--
pom.xml | 41 ++-
8 files changed, 255 insertions(+), 443 deletions(-)
delete mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
index 2de3cf3cb54..e53be5e6696 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
@@ -1392,6 +1392,41 @@ public enum Pointcut {
"ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails"
),
+ /**
+ * Invoked when the storage engine is about to reuse the results of
+ * a previously cached search.
+ *
+ * Hooks may accept the following parameters:
+ *
+ *
+ *
+ * ca.uhn.fhir.jpa.searchparam.SearchParameterMap - Contains the details of the search being checked
+ *
+ *
+ * ca.uhn.fhir.rest.api.server.RequestDetails - A bean containing details about the request that is about to be processed, including details such as the
+ * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
+ * pulled out of the servlet request. Note that the bean
+ * properties are not all guaranteed to be populated, depending on how early during processing the
+ * exception occurred. Note that this parameter may be null in contexts where the request is not
+ * known, such as while processing searches
+ *
+ *
+ * ca.uhn.fhir.rest.server.servlet.ServletRequestDetails - A bean containing details about the request that is about to be processed, including details such as the
+ * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
+ * pulled out of the servlet request. This parameter is identical to the RequestDetails parameter above but will
+ * only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
+ *
+ *
+ *
+ * Hooks should return void.
+ *
+ */
+ JPA_PERFTRACE_SEARCH_REUSING_CACHED(boolean.class,
+ "ca.uhn.fhir.jpa.searchparam.SearchParameterMap",
+ "ca.uhn.fhir.rest.api.server.RequestDetails",
+ "ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"
+ ),
+
/**
* Note that this is a performance tracing hook. Use with caution in production
* systems, since calling it may (or may not) carry a cost.
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
index 76fd4347839..8fbb7f4bb5e 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
@@ -852,10 +852,15 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
private boolean isEncodeExtension(CompositeChildElement theParent, EncodeContext theEncodeContext, boolean theContainedResource, IBase theElement) {
theEncodeContext.pushPath("extension", false);
- BaseRuntimeChildDefinition childDef = ((BaseRuntimeElementCompositeDefinition) myContext.getElementDefinition(theElement.getClass())).getChildByName("extension");
- CompositeChildElement c = new CompositeChildElement(theParent, childDef, theEncodeContext);
- boolean retVal = c.shouldBeEncoded(theContainedResource);
- theEncodeContext.popPath();
+ BaseRuntimeElementDefinition> runtimeElementDefinition = myContext.getElementDefinition(theElement.getClass());
+ boolean retVal = true;
+ if (runtimeElementDefinition instanceof BaseRuntimeElementCompositeDefinition) {
+ BaseRuntimeElementCompositeDefinition definition = (BaseRuntimeElementCompositeDefinition) runtimeElementDefinition;
+ BaseRuntimeChildDefinition childDef = definition.getChildByName("extension");
+ CompositeChildElement c = new CompositeChildElement(theParent, childDef, theEncodeContext);
+ retVal = c.shouldBeEncoded(theContainedResource);
+ theEncodeContext.popPath();
+ }
return retVal;
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
index 8fe6bac3d4f..575f379983c 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
@@ -32,6 +32,7 @@ import ca.uhn.fhir.jpa.entity.ResourceSearchView;
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
import ca.uhn.fhir.jpa.model.entity.*;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
+import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
import ca.uhn.fhir.jpa.model.util.StringNormalizer;
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
@@ -60,7 +61,6 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.util.UrlUtil;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -113,10 +113,6 @@ public class SearchBuilder implements ISearchBuilder {
*/
private static final int MAXIMUM_PAGE_SIZE = 800;
private static Long NO_MORE = -1L;
- private static HandlerTypeEnum ourLastHandlerMechanismForUnitTest;
- private static SearchParameterMap ourLastHandlerParamsForUnitTest;
- private static String ourLastHandlerThreadForUnitTest;
- private static boolean ourTrackHandlersForUnitTest;
private final boolean myDontUseHashesForSearch;
private final DaoConfig myDaoConfig;
@Autowired
@@ -1546,12 +1542,6 @@ public class SearchBuilder implements ISearchBuilder {
myBuilder = myEntityManager.getCriteriaBuilder();
mySearchUuid = theSearchRuntimeDetails.getSearchUuid();
- if (ourTrackHandlersForUnitTest) {
- ourLastHandlerParamsForUnitTest = theParams;
- ourLastHandlerMechanismForUnitTest = HandlerTypeEnum.STANDARD_QUERY;
- ourLastHandlerThreadForUnitTest = Thread.currentThread().getName();
- }
-
if (myPidSet == null) {
myPidSet = new HashSet<>();
}
@@ -2214,9 +2204,16 @@ public class SearchBuilder implements ISearchBuilder {
if (sb != null) {
String indexString = sb.toString();
ourLog.debug("Checking for unique index for query: {}", indexString);
- if (ourTrackHandlersForUnitTest) {
- ourLastHandlerMechanismForUnitTest = HandlerTypeEnum.UNIQUE_INDEX;
- }
+
+ // Interceptor broadcast: JPA_PERFTRACE_INFO
+ StorageProcessingMessage msg = new StorageProcessingMessage()
+ .setMessage("Using unique index for query for search: " + indexString);
+ HookParams params = new HookParams()
+ .add(RequestDetails.class, theRequest)
+ .addIfMatchesType(ServletRequestDetails.class, theRequest)
+ .add(StorageProcessingMessage.class, msg);
+ JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params);
+
addPredicateCompositeStringUnique(theParams, indexString);
}
}
@@ -2788,24 +2785,6 @@ public class SearchBuilder implements ISearchBuilder {
return query.getResultList();
}
- @VisibleForTesting
- public static HandlerTypeEnum getLastHandlerMechanismForUnitTest() {
- return ourLastHandlerMechanismForUnitTest;
- }
-
- @VisibleForTesting
- public static String getLastHandlerParamsForUnitTest() {
- return ourLastHandlerParamsForUnitTest.toString() + " on thread [" + ourLastHandlerThreadForUnitTest + "]";
- }
-
- @VisibleForTesting
- public static void resetLastHandlerMechanismForUnitTest() {
- ourLastHandlerMechanismForUnitTest = null;
- ourLastHandlerParamsForUnitTest = null;
- ourLastHandlerThreadForUnitTest = null;
- ourTrackHandlersForUnitTest = true;
- }
-
private static Predicate[] toArray(List thePredicates) {
return thePredicates.toArray(new Predicate[0]);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
index 91228809799..a6402100d4d 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
@@ -410,6 +410,14 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
PersistedJpaBundleProvider retVal = null;
if (searchToUse != null) {
ourLog.debug("Reusing search {} from cache", searchToUse.getUuid());
+
+ // Interceptor call: JPA_PERFTRACE_SEARCH_REUSING_CACHED
+ params = new HookParams()
+ .add(SearchParameterMap.class, theParams)
+ .add(RequestDetails.class, theRequestDetails)
+ .addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
+ JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequestDetails, Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED, params);
+
searchToUse.setSearchLastReturned(new Date());
mySearchDao.updateSearchLastReturned(searchToUse.getId(), new Date());
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java
index 54be5d46320..c33c0e8f50b 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java
@@ -5,7 +5,6 @@ import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
-import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
@@ -104,7 +103,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
DataSource dataSource = ProxyDataSourceBuilder
.create(retVal)
- .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
+// .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
// .logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
// .countQuery(new ThreadQueryCountHolder())
.beforeQuery(new BlockLargeNumbersOfParamsListener())
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java
deleted file mode 100644
index e648d839c7a..00000000000
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3UniqueSearchParamTest.java
+++ /dev/null
@@ -1,345 +0,0 @@
-package ca.uhn.fhir.jpa.dao.dstu3;
-
-import ca.uhn.fhir.jpa.dao.SearchBuilder;
-import ca.uhn.fhir.jpa.model.entity.ModelConfig;
-import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
-import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
-import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
-import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
-import ca.uhn.fhir.rest.api.server.IBundleProvider;
-import ca.uhn.fhir.rest.param.DateParam;
-import ca.uhn.fhir.rest.param.TokenParam;
-import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
-import ca.uhn.fhir.util.TestUtil;
-import org.hl7.fhir.dstu3.model.*;
-import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.test.context.TestPropertySource;
-
-import java.util.List;
-
-import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.empty;
-import static org.junit.Assert.*;
-
-@SuppressWarnings({"unchecked", "deprecation"})
-@TestPropertySource(properties = {
- // Since scheduled tasks can cause searches, which messes up the
- // value returned by SearchBuilder.getLastHandlerMechanismForUnitTest()
- "scheduling_disabled=true"
-})
-public class FhirResourceDaoDstu3UniqueSearchParamTest extends BaseJpaDstu3Test {
-
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3UniqueSearchParamTest.class);
-
- @After
- public void after() {
- myModelConfig.setDefaultSearchParamsCanBeOverridden(new ModelConfig().isDefaultSearchParamsCanBeOverridden());
- }
-
- @Before
- public void before() {
- myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
- }
-
- private void createUniqueBirthdateAndGenderSps() {
- SearchParameter sp = new SearchParameter();
- sp.setId("SearchParameter/patient-gender");
- sp.setType(Enumerations.SearchParamType.TOKEN);
- sp.setCode("gender");
- sp.setExpression("Patient.gender");
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Patient");
- mySearchParameterDao.update(sp);
-
- sp = new SearchParameter();
- sp.setId("SearchParameter/patient-birthdate");
- sp.setType(Enumerations.SearchParamType.DATE);
- sp.setCode("birthdate");
- sp.setExpression("Patient.birthDate");
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Patient");
- mySearchParameterDao.update(sp);
-
- sp = new SearchParameter();
- sp.setId("SearchParameter/patient-gender-birthdate");
- sp.setType(Enumerations.SearchParamType.COMPOSITE);
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Patient");
- sp.addComponent()
- .setExpression("Patient")
- .setDefinition(new Reference("SearchParameter/patient-gender"));
- sp.addComponent()
- .setExpression("Patient")
- .setDefinition(new Reference("SearchParameter/patient-birthdate"));
- sp.addExtension()
- .setUrl(SearchParamConstants.EXT_SP_UNIQUE)
- .setValue(new BooleanType(true));
- mySearchParameterDao.update(sp);
-
- mySearchParamRegistry.forceRefresh();
- }
-
- private void createUniqueIndexCoverageBeneficiary() {
- SearchParameter sp = new SearchParameter();
- sp.setId("SearchParameter/coverage-beneficiary");
- sp.setCode("beneficiary");
- sp.setExpression("Coverage.beneficiary");
- sp.setType(Enumerations.SearchParamType.REFERENCE);
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Coverage");
- mySearchParameterDao.update(sp);
-
- sp = new SearchParameter();
- sp.setId("SearchParameter/coverage-identifier");
- sp.setCode("identifier");
- sp.setExpression("Coverage.identifier");
- sp.setType(Enumerations.SearchParamType.TOKEN);
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Coverage");
- mySearchParameterDao.update(sp);
-
- sp = new SearchParameter();
- sp.setId("SearchParameter/coverage-beneficiary-identifier");
- sp.setCode("coverage-beneficiary-identifier");
- sp.setExpression("Coverage.beneficiary");
- sp.setType(Enumerations.SearchParamType.COMPOSITE);
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Coverage");
- sp.addComponent()
- .setExpression("Coverage")
- .setDefinition(new Reference("/SearchParameter/coverage-beneficiary"));
- sp.addComponent()
- .setExpression("Coverage")
- .setDefinition(new Reference("/SearchParameter/coverage-identifier"));
- sp.addExtension()
- .setUrl(SearchParamConstants.EXT_SP_UNIQUE)
- .setValue(new BooleanType(true));
- mySearchParameterDao.update(sp);
- mySearchParamRegistry.forceRefresh();
- }
-
- private void createUniqueNameAndManagingOrganizationSps() {
- SearchParameter sp = new SearchParameter();
- sp.setId("SearchParameter/patient-name");
- sp.setType(Enumerations.SearchParamType.STRING);
- sp.setCode("name");
- sp.setExpression("Patient.name");
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Patient");
- mySearchParameterDao.update(sp);
-
- sp = new SearchParameter();
- sp.setId("SearchParameter/patient-organization");
- sp.setType(Enumerations.SearchParamType.REFERENCE);
- sp.setCode("organization");
- sp.setExpression("Patient.managingOrganization");
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Patient");
- mySearchParameterDao.update(sp);
-
- sp = new SearchParameter();
- sp.setId("SearchParameter/patient-name-organization");
- sp.setType(Enumerations.SearchParamType.COMPOSITE);
- sp.setStatus(PublicationStatus.ACTIVE);
- sp.addBase("Patient");
- sp.addComponent()
- .setExpression("Patient")
- .setDefinition(new Reference("SearchParameter/patient-name"));
- sp.addComponent()
- .setExpression("Patient")
- .setDefinition(new Reference("SearchParameter/patient-organization"));
- sp.addExtension()
- .setUrl(SearchParamConstants.EXT_SP_UNIQUE)
- .setValue(new BooleanType(true));
- mySearchParameterDao.update(sp);
-
- mySearchParamRegistry.forceRefresh();
- }
-
- @Test
- public void testDetectUniqueSearchParams() {
- createUniqueBirthdateAndGenderSps();
- List params = mySearchParamRegistry.getActiveUniqueSearchParams("Patient");
-
- assertEquals(1, params.size());
- assertEquals(params.get(0).isUnique(), true);
- assertEquals(2, params.get(0).getCompositeOf().size());
- // Should be alphabetical order
- assertEquals("birthdate", params.get(0).getCompositeOf().get(0).getName());
- assertEquals("gender", params.get(0).getCompositeOf().get(1).getName());
- }
-
- @Test
- public void testDuplicateUniqueValuesAreRejected() {
- createUniqueBirthdateAndGenderSps();
-
- Patient pt1 = new Patient();
- pt1.setGender(Enumerations.AdministrativeGender.MALE);
- pt1.setBirthDateElement(new DateType("2011-01-01"));
- IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
-
- try {
- myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
- fail();
- } catch (PreconditionFailedException e) {
- // good
- }
-
- Patient pt2 = new Patient();
- pt2.setGender(Enumerations.AdministrativeGender.MALE);
- IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
-
- pt2 = new Patient();
- pt2.setId(id2);
- pt2.setGender(Enumerations.AdministrativeGender.MALE);
- pt2.setBirthDateElement(new DateType("2011-01-01"));
- try {
- myPatientDao.update(pt2);
- fail();
- } catch (PreconditionFailedException e) {
- // good
- }
-
- }
-
- @Test
- public void testReplaceOneWithAnother() {
- createUniqueBirthdateAndGenderSps();
-
- Patient pt1 = new Patient();
- pt1.setGender(Enumerations.AdministrativeGender.MALE);
- pt1.setBirthDateElement(new DateType("2011-01-01"));
- IIdType id1 = myPatientDao.create(pt1).getId().toUnqualified();
- assertNotNull(id1);
-
- ourLog.info("** Replacing");
-
- pt1 = new Patient();
- pt1.setId(id1);
- pt1.setGender(Enumerations.AdministrativeGender.FEMALE);
- pt1.setBirthDateElement(new DateType("2011-01-01"));
- id1 = myPatientDao.update(pt1).getId().toUnqualified();
- assertNotNull(id1);
- assertEquals("2", id1.getVersionIdPart());
-
- Patient pt2 = new Patient();
- pt2.setGender(Enumerations.AdministrativeGender.MALE);
- pt2.setBirthDateElement(new DateType("2011-01-01"));
- IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
-
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- SearchParameterMap params = new SearchParameterMap();
- params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
- params.add("birthdate", new DateParam("2011-01-01"));
- IBundleProvider results = myPatientDao.search(params);
- String searchId = results.getUuid();
- assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id2.getValue()));
- assertEquals(SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
-
- }
-
- @Test
- public void testSearchSynchronousUsingUniqueComposite() {
- createUniqueBirthdateAndGenderSps();
-
- Patient pt1 = new Patient();
- pt1.setGender(Enumerations.AdministrativeGender.MALE);
- pt1.setBirthDateElement(new DateType("2011-01-01"));
- IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
-
- Patient pt2 = new Patient();
- pt2.setGender(Enumerations.AdministrativeGender.MALE);
- pt2.setBirthDateElement(new DateType("2011-01-02"));
- IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
-
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- SearchParameterMap params = new SearchParameterMap();
- params.setLoadSynchronousUpTo(100);
- params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
- params.add("birthdate", new DateParam("2011-01-01"));
- IBundleProvider results = myPatientDao.search(params);
- assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1.getValue()));
- assertEquals(SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
- }
-
- @Test
- public void testSearchUsingUniqueComposite() {
- createUniqueBirthdateAndGenderSps();
-
- Patient pt1 = new Patient();
- pt1.setGender(Enumerations.AdministrativeGender.MALE);
- pt1.setBirthDateElement(new DateType("2011-01-01"));
- IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
- assertNotNull(id1);
-
- Patient pt2 = new Patient();
- pt2.setGender(Enumerations.AdministrativeGender.MALE);
- pt2.setBirthDateElement(new DateType("2011-01-02"));
- IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
-
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- SearchParameterMap params = new SearchParameterMap();
- params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
- params.add("birthdate", new DateParam("2011-01-01"));
- IBundleProvider results = myPatientDao.search(params);
- String searchId = results.getUuid();
- assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1.getValue()));
- assertEquals(SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
-
- // Other order
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- params = new SearchParameterMap();
- params.add("birthdate", new DateParam("2011-01-01"));
- params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
- results = myPatientDao.search(params);
- assertEquals(searchId, results.getUuid());
- String id1Value = id1.getValue();
- List actualValues = toUnqualifiedVersionlessIdValues(results);
- assertThat(actualValues, containsInAnyOrder(id1Value));
- // Null because we just reuse the last search
- assertEquals(null, SearchBuilder.getLastHandlerMechanismForUnitTest());
-
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- params = new SearchParameterMap();
- params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
- params.add("birthdate", new DateParam("2011-01-03"));
- results = myPatientDao.search(params);
- assertThat(toUnqualifiedVersionlessIdValues(results), empty());
- assertEquals(SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
-
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- params = new SearchParameterMap();
- params.add("birthdate", new DateParam("2011-01-03"));
- results = myPatientDao.search(params);
- assertThat(toUnqualifiedVersionlessIdValues(results), empty());
- assertEquals(SearchBuilder.HandlerTypeEnum.STANDARD_QUERY, SearchBuilder.getLastHandlerMechanismForUnitTest());
-
- }
-
- @Test
- public void testUniqueValuesAreIndexed_DateAndToken() {
- createUniqueBirthdateAndGenderSps();
-
- Patient pt1 = new Patient();
- pt1.setGender(Enumerations.AdministrativeGender.MALE);
- pt1.setBirthDateElement(new DateType("2011-01-01"));
- IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
-
- List uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
- assertEquals(1, uniques.size());
- assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
- assertEquals("Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale", uniques.get(0).getIndexString());
- }
-
- @AfterClass
- public static void afterClassClearContext() {
- TestUtil.clearAllStaticFieldsForUnitTest();
- }
-
-
-}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java
index def1b97383d..8e621e7f504 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java
@@ -1,15 +1,18 @@
package ca.uhn.fhir.jpa.dao.r4;
+import ca.uhn.fhir.interceptor.api.HookParams;
+import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
+import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.dao.DaoConfig;
-import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
+import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
-import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
@@ -17,6 +20,7 @@ import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
+import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
@@ -25,6 +29,7 @@ import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentMatchers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.TransactionStatus;
@@ -32,6 +37,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nonnull;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -40,8 +46,10 @@ import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.INDEX_STATUS_INDEXED;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-@SuppressWarnings({"unchecked", "deprecation"})
@TestPropertySource(properties = {
// Since scheduled tasks can cause searches, which messes up the
// value returned by SearchBuilder.getLastHandlerMechanismForUnitTest()
@@ -52,6 +60,8 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4UniqueSearchParamTest.class);
@Autowired
private ISearchParamRegistry mySearchParamRegistry;
+ private IInterceptorBroadcaster myInterceptorBroadcaster;
+ private List myMessages = new ArrayList<>();
@After
public void after() {
@@ -66,9 +76,31 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
myDaoConfig.setSchedulingDisabled(true);
myDaoConfig.setUniqueIndexesEnabled(true);
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
+
+ myInterceptorBroadcaster = mock(IInterceptorBroadcaster.class);
+ when(mySrd.getInterceptorBroadcaster()).thenReturn(myInterceptorBroadcaster);
+ when(mySrd.getServer().getPagingProvider()).thenReturn(new DatabaseBackedPagingProvider());
+
+ when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_WARNING))).thenReturn(true);
+ when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_INFO))).thenReturn(true);
+ when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_INFO), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
+ HookParams params = t.getArgument(1, HookParams.class);
+ myMessages.add("INFO " + params.get(StorageProcessingMessage.class).getMessage());
+ return null;
+ });
+ when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_WARNING), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
+ HookParams params = t.getArgument(1, HookParams.class);
+ myMessages.add("WARN " + params.get(StorageProcessingMessage.class).getMessage());
+ return null;
+ });
+ when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
+ HookParams params = t.getArgument(1, HookParams.class);
+ myMessages.add("REUSING CACHED SEARCH");
+ return null;
+ });
}
+
private void createUniqueBirthdateAndGenderSps() {
SearchParameter sp = new SearchParameter();
sp.setId("SearchParameter/patient-gender");
@@ -106,7 +138,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
mySearchParamRegistry.forceRefresh();
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
+ myMessages.clear();
}
private void createUniqueIndexCoverageBeneficiary() {
@@ -322,19 +354,6 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
mySearchParamRegistry.forceRefresh();
}
- @Test
- public void testDetectUniqueSearchParams() {
- createUniqueBirthdateAndGenderSps();
- List params = mySearchParamRegistry.getActiveUniqueSearchParams("Patient");
-
- assertEquals(1, params.size());
- assertTrue(params.get(0).isUnique());
- assertEquals(2, params.get(0).getCompositeOf().size());
- // Should be alphabetical order
- assertEquals("birthdate", params.get(0).getCompositeOf().get(0).getName());
- assertEquals("gender", params.get(0).getCompositeOf().get(1).getName());
- }
-
@Test
public void testDoubleMatchingOnAnd_Search() {
createUniqueIndexPatientIdentifier();
@@ -981,15 +1000,19 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
myCaptureQueriesListener.clear();
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
+ myMessages.clear();
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(100);
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
params.add("birthdate", new DateParam("2011-01-01"));
- IBundleProvider results = myPatientDao.search(params);
+ IBundleProvider results = myPatientDao.search(params, mySrd);
myCaptureQueriesListener.logFirstSelectQueryForCurrentThread();
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1.getValue()));
- assertEquals(SearchBuilder.getLastHandlerParamsForUnitTest(), SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
+
+ logCapturedMessages();
+ assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
+ myMessages.clear();
+
}
@@ -1007,40 +1030,50 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
pt2.setBirthDateElement(new DateType("2011-01-02"));
myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
+ myMessages.clear();
SearchParameterMap params = new SearchParameterMap();
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
params.add("birthdate", new DateParam("2011-01-01"));
- IBundleProvider results = myPatientDao.search(params);
+ IBundleProvider results = myPatientDao.search(params, mySrd);
String searchId = results.getUuid();
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1));
- assertEquals(SearchBuilder.getLastHandlerParamsForUnitTest(), SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
+ logCapturedMessages();
+ assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
+ myMessages.clear();
// Other order
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
+ myMessages.clear();
params = new SearchParameterMap();
params.add("birthdate", new DateParam("2011-01-01"));
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
- results = myPatientDao.search(params);
+ results = myPatientDao.search(params, mySrd);
assertEquals(searchId, results.getUuid());
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1));
- // Null because we just reuse the last search
- assertNull(SearchBuilder.getLastHandlerMechanismForUnitTest());
+ // Because we just reuse the last search
+ logCapturedMessages();
+ assertThat(myMessages.toString(), containsString("REUSING"));
+ assertThat(myMessages.toString(), not(containsString("Using unique index")));
+ myMessages.clear();
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
+ myMessages.clear();
params = new SearchParameterMap();
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
params.add("birthdate", new DateParam("2011-01-03"));
- results = myPatientDao.search(params);
+ results = myPatientDao.search(params, mySrd);
assertThat(toUnqualifiedVersionlessIdValues(results), empty());
- assertEquals(SearchBuilder.getLastHandlerParamsForUnitTest(), SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
+ logCapturedMessages();
+ assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-03&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
+ myMessages.clear();
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
+ myMessages.clear();
params = new SearchParameterMap();
params.add("birthdate", new DateParam("2011-01-03"));
- results = myPatientDao.search(params);
+ results = myPatientDao.search(params, mySrd);
assertThat(toUnqualifiedVersionlessIdValues(results), empty());
- assertEquals(SearchBuilder.getLastHandlerParamsForUnitTest(), SearchBuilder.HandlerTypeEnum.STANDARD_QUERY, SearchBuilder.getLastHandlerMechanismForUnitTest());
+ // STANDARD QUERY
+ logCapturedMessages();
+ assertThat(myMessages.toString(), not(containsString("unique index")));
+ myMessages.clear();
}
@@ -1104,9 +1137,12 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
pt1.addName().setFamily("FAMILY1");
pt1.setManagingOrganization(new Reference("Organization/ORG"));
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- IIdType id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG").getId().toUnqualifiedVersionless();
- assertEquals(SearchBuilder.getLastHandlerParamsForUnitTest(), SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
+ IIdType id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG", mySrd).getId().toUnqualifiedVersionless();
+
+ logCapturedMessages();
+ assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?name=FAMILY1&organization=Organization%2FORG"));
+ myMessages.clear();
+
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
assertEquals(1, uniques.size());
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
@@ -1118,9 +1154,12 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
pt1.addName().setFamily("FAMILY1");
pt1.setManagingOrganization(new Reference("Organization/ORG"));
- SearchBuilder.resetLastHandlerMechanismForUnitTest();
- id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG").getId().toUnqualifiedVersionless();
- assertEquals(SearchBuilder.getLastHandlerParamsForUnitTest(), SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
+ id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG", mySrd).getId().toUnqualifiedVersionless();
+
+ logCapturedMessages();
+ assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?name=FAMILY1&organization=Organization%2FORG"));
+ myMessages.clear();
+
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
assertEquals(1, uniques.size());
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
@@ -1128,6 +1167,10 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
}
+ private void logCapturedMessages() {
+ ourLog.info("Messages:\n {}", String.join("\n ", myMessages));
+ }
+
@Test
public void testUniqueValuesAreIndexed_StringAndReference() {
createUniqueNameAndManagingOrganizationSps();
@@ -1375,6 +1418,93 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
}
+
+ @Test
+ public void testDetectUniqueSearchParams() {
+ createUniqueBirthdateAndGenderSps();
+ List params = mySearchParamRegistry.getActiveUniqueSearchParams("Patient");
+
+ assertEquals(1, params.size());
+ assertEquals(params.get(0).isUnique(), true);
+ assertEquals(2, params.get(0).getCompositeOf().size());
+ // Should be alphabetical order
+ assertEquals("birthdate", params.get(0).getCompositeOf().get(0).getName());
+ assertEquals("gender", params.get(0).getCompositeOf().get(1).getName());
+ }
+
+ @Test
+ public void testDuplicateUniqueValuesAreRejected() {
+ createUniqueBirthdateAndGenderSps();
+
+ Patient pt1 = new Patient();
+ pt1.setGender(Enumerations.AdministrativeGender.MALE);
+ pt1.setBirthDateElement(new DateType("2011-01-01"));
+ IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
+
+ try {
+ myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
+ fail();
+ } catch (PreconditionFailedException e) {
+ // good
+ }
+
+ Patient pt2 = new Patient();
+ pt2.setGender(Enumerations.AdministrativeGender.MALE);
+ IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
+
+ pt2 = new Patient();
+ pt2.setId(id2);
+ pt2.setGender(Enumerations.AdministrativeGender.MALE);
+ pt2.setBirthDateElement(new DateType("2011-01-01"));
+ try {
+ myPatientDao.update(pt2);
+ fail();
+ } catch (PreconditionFailedException e) {
+ // good
+ }
+
+ }
+
+ @Test
+ public void testReplaceOneWithAnother() {
+ createUniqueBirthdateAndGenderSps();
+
+ Patient pt1 = new Patient();
+ pt1.setGender(Enumerations.AdministrativeGender.MALE);
+ pt1.setBirthDateElement(new DateType("2011-01-01"));
+ IIdType id1 = myPatientDao.create(pt1).getId().toUnqualified();
+ assertNotNull(id1);
+
+ ourLog.info("** Replacing");
+
+ pt1 = new Patient();
+ pt1.setId(id1);
+ pt1.setGender(Enumerations.AdministrativeGender.FEMALE);
+ pt1.setBirthDateElement(new DateType("2011-01-01"));
+ id1 = myPatientDao.update(pt1).getId().toUnqualified();
+ assertNotNull(id1);
+ assertEquals("2", id1.getVersionIdPart());
+
+ Patient pt2 = new Patient();
+ pt2.setGender(Enumerations.AdministrativeGender.MALE);
+ pt2.setBirthDateElement(new DateType("2011-01-01"));
+ IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
+
+ myMessages.clear();
+ SearchParameterMap params = new SearchParameterMap();
+ params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
+ params.add("birthdate", new DateParam("2011-01-01"));
+ IBundleProvider results = myPatientDao.search(params, mySrd);
+ String searchId = results.getUuid();
+ assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id2.getValue()));
+
+ logCapturedMessages();
+ assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
+ myMessages.clear();
+
+ }
+
+
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
diff --git a/pom.xml b/pom.xml
index 217eefd7495..0f48b01b040 100755
--- a/pom.xml
+++ b/pom.xml
@@ -1792,23 +1792,6 @@
-
- org.codehaus.mojo
- license-maven-plugin
- false
-
-
- update-project-license
- package
-
- update-project-license
-
-
- apache_v2
-
-
-
- maven-antrun-pluginfalse
@@ -2196,9 +2179,27 @@
DIST
-
-
-
+
+
+
+ org.codehaus.mojo
+ license-maven-plugin
+ false
+
+
+ update-project-license
+ package
+
+ update-project-license
+
+
+ apache_v2
+
+
+
+
+
+ ROOT
From a352137938a901df721d3c82812d4231dff619f4 Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Thu, 11 Jul 2019 21:10:30 -0400
Subject: [PATCH 07/10] Test fixes
---
.../java/ca/uhn/fhir/parser/JsonParser.java | 6 +-
.../uhn/fhir/parser/JsonParserDstu3Test.java | 126 ++++++------------
.../fhir/rest/server/ElementsParamR4Test.java | 10 ++
3 files changed, 52 insertions(+), 90 deletions(-)
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
index 8fbb7f4bb5e..d391be8c3df 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
@@ -851,7 +851,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
private boolean isEncodeExtension(CompositeChildElement theParent, EncodeContext theEncodeContext, boolean theContainedResource, IBase theElement) {
- theEncodeContext.pushPath("extension", false);
+// theEncodeContext.pushPath("extension", false);
BaseRuntimeElementDefinition> runtimeElementDefinition = myContext.getElementDefinition(theElement.getClass());
boolean retVal = true;
if (runtimeElementDefinition instanceof BaseRuntimeElementCompositeDefinition) {
@@ -859,8 +859,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
BaseRuntimeChildDefinition childDef = definition.getChildByName("extension");
CompositeChildElement c = new CompositeChildElement(theParent, childDef, theEncodeContext);
retVal = c.shouldBeEncoded(theContainedResource);
- theEncodeContext.popPath();
}
+// theEncodeContext.popPath();
return retVal;
}
@@ -1516,6 +1516,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
// Write value
if (!noValue) {
+ theEncodeContext.pushPath("value", false);
/*
* Pre-process value - This is called in case the value is a reference
@@ -1535,6 +1536,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, false, myParent,false, theEncodeContext);
managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName, theEncodeContext, theContainedResource);
+ theEncodeContext.popPath();
}
}
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
index 9256172561d..2a9e8f42798 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
@@ -18,9 +18,9 @@ import net.sf.json.JsonConfig;
import org.apache.commons.io.IOUtils;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
+import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Address.AddressUse;
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
-import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.CapabilityStatement.UnknownContentCode;
@@ -33,7 +33,6 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.junit.*;
import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
import java.io.IOException;
import java.io.StringReader;
@@ -45,9 +44,8 @@ import static org.apache.commons.lang3.StringUtils.countMatches;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.*;
@@ -110,16 +108,16 @@ public class JsonParserDstu3Test {
// Deserialize then check that valueReference value is still correct
fhirPat = parser.parseResource(Patient.class, output);
- List extlst = fhirPat.getExtensionsByUrl("x1");
- Assert.assertEquals(1, extlst.size());
- Assert.assertEquals(refVal, ((Reference) extlst.get(0).getValue()).getReference());
+ List extensions = fhirPat.getExtensionsByUrl("x1");
+ Assert.assertEquals(1, extensions.size());
+ Assert.assertEquals(refVal, ((Reference) extensions.get(0).getValue()).getReference());
}
/**
* See #544
*/
@Test
- public void testBundleStitchReferencesByUuid() throws Exception {
+ public void testBundleStitchReferencesByUuid() {
Bundle bundle = new Bundle();
DocumentManifest dm = new DocumentManifest();
@@ -175,7 +173,7 @@ public class JsonParserDstu3Test {
}
@Test
- public void testCustomUrlExtensioninBundle() {
+ public void testCustomUrlExtensionInBundle() {
final String expected = "{\"resourceType\":\"Bundle\",\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://www.example.com/petname\",\"valueString\":\"myName\"}]}}]}";
final MyPatientWithCustomUrlExtension patient = new MyPatientWithCustomUrlExtension();
@@ -213,7 +211,7 @@ public class JsonParserDstu3Test {
* See #276
*/
@Test
- public void testDoubleEncodingContainedResources() throws Exception {
+ public void testDoubleEncodingContainedResources() {
Patient patient = new Patient();
patient.setId("#patient-1");
patient.setActive(true);
@@ -236,7 +234,7 @@ public class JsonParserDstu3Test {
}
@Test
- public void testEncodeAndParseExtensions() throws Exception {
+ public void testEncodeAndParseExtensions() {
Patient patient = new Patient();
patient.addIdentifier().setUse(IdentifierUse.OFFICIAL).setSystem("urn:example").setValue("7000135");
@@ -402,6 +400,7 @@ public class JsonParserDstu3Test {
/**
* See #336
*/
+ @SuppressWarnings("SpellCheckingInspection")
@Test
public void testEncodeAndParseNullPrimitiveWithExtensions() {
@@ -458,7 +457,7 @@ public class JsonParserDstu3Test {
Patient p = new Patient();
p.addName().setFamily("FAMILY");
- List labels = new ArrayList();
+ List labels = new ArrayList<>();
labels.add(new Coding().setSystem("SYSTEM1").setCode("CODE1").setDisplay("DISPLAY1").setVersion("VERSION1"));
labels.add(new Coding().setSystem("SYSTEM2").setCode("CODE2").setDisplay("DISPLAY2").setVersion("VERSION2"));
p.getMeta().getSecurity().addAll(labels);
@@ -602,7 +601,7 @@ public class JsonParserDstu3Test {
*/
@Test
public void testEncodeEmptyTag() {
- ArrayList tagList = new ArrayList();
+ ArrayList tagList = new ArrayList<>();
tagList.add(new Coding());
tagList.add(new Coding().setDisplay("Label"));
@@ -618,7 +617,7 @@ public class JsonParserDstu3Test {
*/
@Test
public void testEncodeEmptyTag2() {
- ArrayList tagList = new ArrayList();
+ ArrayList tagList = new ArrayList<>();
tagList.add(new Coding().setSystem("scheme").setCode("code"));
tagList.add(new Coding().setDisplay("Label"));
@@ -731,8 +730,8 @@ public class JsonParserDstu3Test {
encoded = parser.encodeResourceToString(p);
ourLog.info(encoded);
- assertThat(encoded, (containsString("http://foo")));
- assertThat(encoded, (containsString("Practitioner/A")));
+ assertThat(encoded, not(containsString("http://foo")));
+ assertThat(encoded, not(containsString("Practitioner/A")));
}
@@ -831,7 +830,7 @@ public class JsonParserDstu3Test {
TestPatientFor327 patient = new TestPatientFor327();
patient.setBirthDateElement(new DateType("2016-04-14"));
- List conditions = new ArrayList();
+ List conditions = new ArrayList<>();
Condition condition = new Condition();
condition.addBodySite().setText("BODY SITE");
conditions.add(new Reference(condition));
@@ -909,7 +908,7 @@ public class JsonParserDstu3Test {
ourLog.info(enc);
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
- parser.setDontStripVersionsFromReferencesAtPaths(new ArrayList());
+ parser.setDontStripVersionsFromReferencesAtPaths(new ArrayList<>());
enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
ourLog.info(enc);
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2\""));
@@ -943,12 +942,12 @@ public class JsonParserDstu3Test {
ourLog.info(enc);
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
- ourCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(Arrays.asList("Patient.managingOrganization"));
+ ourCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(Collections.singletonList("Patient.managingOrganization"));
enc = parser.setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(enc);
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
- ourCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(new HashSet(Arrays.asList("Patient.managingOrganization")));
+ ourCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(new HashSet<>(Collections.singletonList("Patient.managingOrganization")));
enc = parser.setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(enc);
assertThat(enc, containsString("\"reference\": \"http://foo.com/Organization/2/_history/1\""));
@@ -1026,7 +1025,7 @@ public class JsonParserDstu3Test {
}
@Test
- public void testEncodeNarrativeSuppressed() throws Exception {
+ public void testEncodeNarrativeSuppressed() {
Patient patient = new Patient();
patient.setId("Patient/1/_history/1");
patient.getText().setDivAsString("
THE DIV
");
@@ -1171,7 +1170,7 @@ public class JsonParserDstu3Test {
* See #241
*/
@Test
- public void testEncodeThenParseShouldNotAddSpuriousId() throws Exception {
+ public void testEncodeThenParseShouldNotAddSpuriousId() {
Condition condition = new Condition().setVerificationStatus(ConditionVerificationStatus.CONFIRMED);
Bundle bundle = new Bundle();
BundleEntryComponent entry = new Bundle.BundleEntryComponent();
@@ -1190,7 +1189,7 @@ public class JsonParserDstu3Test {
}
@Test
- public void testEncodeUndeclaredBlock() throws Exception {
+ public void testEncodeUndeclaredBlock() {
FooMessageHeader.FooMessageSourceComponent source = new FooMessageHeader.FooMessageSourceComponent();
source.getMessageHeaderApplicationId().setValue("APPID");
source.setName("NAME");
@@ -1217,7 +1216,7 @@ public class JsonParserDstu3Test {
Patient patient = new Patient();
patient.addAddress().setUse(AddressUse.HOME);
EnumFactory fact = new AddressUseEnumFactory();
- PrimitiveType enumeration = new Enumeration(fact).setValue(AddressUse.HOME);
+ PrimitiveType enumeration = new Enumeration<>(fact).setValue(AddressUse.HOME);
patient.addExtension().setUrl("urn:foo").setValue(enumeration);
String val = parser.encodeResourceToString(patient);
@@ -1232,7 +1231,7 @@ public class JsonParserDstu3Test {
}
@Test
- public void testEncodeWithDontEncodeElements() throws Exception {
+ public void testEncodeWithDontEncodeElements() {
Patient patient = new Patient();
patient.setId("123");
@@ -1288,7 +1287,7 @@ public class JsonParserDstu3Test {
{
IParser p = ourCtx.newJsonParser();
p.setDontEncodeElements(Sets.newHashSet("Patient.meta"));
- p.setEncodeElements(new HashSet(Arrays.asList("Patient.name")));
+ p.setEncodeElements(new HashSet<>(Collections.singletonList("Patient.name")));
p.setPrettyPrint(true);
String out = p.encodeResourceToString(patient);
ourLog.info(out);
@@ -1502,7 +1501,7 @@ public class JsonParserDstu3Test {
String res = "{ \"resourceType\": \"ValueSet\", \"url\": \"http://sample/ValueSet/education-levels\", \"version\": \"1\", \"name\": \"Education Levels\", \"status\": \"draft\", \"compose\": { \"include\": [ { \"filter\": [ { \"property\": \"n\", \"op\": \"n\", \"value\": \"365460000\" } ], \"system\": \"http://snomed.info/sct\" } ], \"exclude\": [ { \"concept\": [ { \"code\": \"224298008\" }, { \"code\": \"365460000\" }, { \"code\": \"473462005\" }, { \"code\": \"424587006\" } ], \"system\": \"http://snomed.info/sct\" } ] }, \"description\": \"A selection of Education Levels\", \"text\": { \"status\": \"generated\", \"div\": \"