();
- String[] paragraphs = html.replace("", "").split("<\\/p>|
");
- for (int i=0;i htmlFormattingToPieces(String html) {
- List myPieces = new ArrayList();
- //Todo: At least handle bold and italics and turn them into formatted spans. (Will need to handle nesting though)
- myPieces.add(new Piece(null, html, null));
-
- return myPieces;
- }
+// private List htmlToParagraphPieces(String html) {
+// List myPieces = new ArrayList();
+// String[] paragraphs = html.replace("", "").split("<\\/p>|
");
+// for (int i=0;i htmlFormattingToPieces(String html) {
+// List myPieces = new ArrayList();
+// //Todo: At least handle bold and italics and turn them into formatted spans. (Will need to handle nesting though)
+// myPieces.add(new Piece(null, html, null));
+//
+// return myPieces;
+// }
public void addStyle(String style) {
for (Piece p : pieces)
p.addStyle(style);
@@ -507,8 +507,8 @@ public class HierarchicalTableGenerator {
b.append(new String(Base64.encodeBase64(bytes)));
// files.put(filename, b.toString());
return b.toString();
- } else
- return corePrefix+filename;
+ }
+ return corePrefix+filename;
}
@@ -558,22 +558,22 @@ public class HierarchicalTableGenerator {
b.append(new String(encodeBase64));
files.put(filename, b.toString());
return b.toString();
- } else {
- b.append("tbl_bck");
- for (Boolean i : indents)
- b.append(i ? "0" : "1");
- if (hasChildren)
- b.append("1");
- else
- b.append("0");
- b.append(".png");
- String file = Utilities.path(dest, b.toString());
- if (!new File(file).exists()) {
- FileOutputStream stream = new FileOutputStream(file);
- genImage(indents, hasChildren, stream);
- }
- return b.toString();
}
+ b.append("tbl_bck");
+ for (Boolean i : indents)
+ b.append(i ? "0" : "1");
+ if (hasChildren)
+ b.append("1");
+ else
+ b.append("0");
+ b.append(".png");
+ String file = Utilities.path(dest, b.toString());
+ if (!new File(file).exists()) {
+ //FIXME resource leak
+ FileOutputStream stream = new FileOutputStream(file);
+ genImage(indents, hasChildren, stream);
+ }
+ return b.toString();
}
diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlDocument.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlDocument.java
index 114f187c296..a4c6b19fbdf 100644
--- a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlDocument.java
+++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlDocument.java
@@ -25,7 +25,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-*/
+ */
package org.hl7.fhir.utilities.xhtml;
/*
@@ -51,15 +51,17 @@ package org.hl7.fhir.utilities.xhtml;
public class XhtmlDocument extends XhtmlNode {
- public XhtmlDocument() {
- super(NodeType.Document);
- }
+ private static final long serialVersionUID = -5061185698841745693L;
- public XhtmlNode getDocumentElement() {
- for (XhtmlNode n : getChildNodes()) {
- if (n.getNodeType() == NodeType.Element)
- return n;
- }
- return null;
- }
+ public XhtmlDocument() {
+ super(NodeType.Document);
+ }
+
+ public XhtmlNode getDocumentElement() {
+ for (XhtmlNode n : getChildNodes()) {
+ if (n.getNodeType() == NodeType.Element)
+ return n;
+ }
+ return null;
+ }
}
diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java
index 4dac3bc76d5..a263b3d945c 100644
--- a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java
+++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java
@@ -25,7 +25,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-*/
+ */
package org.hl7.fhir.utilities.xhtml;
/*
@@ -62,268 +62,268 @@ import ca.uhn.fhir.model.primitive.XhtmlDt;
@ca.uhn.fhir.model.api.annotation.DatatypeDef(name="xhtml")
public class XhtmlNode implements IBaseXhtml {
- private static final long serialVersionUID = -4362547161441436492L;
+ private static final long serialVersionUID = -4362547161441436492L;
- public static class Location {
- private int line;
- private int column;
- public Location(int line, int column) {
- super();
- this.line = line;
- this.column = column;
- }
- public int getLine() {
- return line;
- }
- public int getColumn() {
- return column;
- }
- @Override
- public String toString() {
- return "Line "+Integer.toString(line)+", column "+Integer.toString(column);
- }
- }
+ public static class Location {
+ private int line;
+ private int column;
+ public Location(int line, int column) {
+ super();
+ this.line = line;
+ this.column = column;
+ }
+ public int getLine() {
+ return line;
+ }
+ public int getColumn() {
+ return column;
+ }
+ @Override
+ public String toString() {
+ return "Line "+Integer.toString(line)+", column "+Integer.toString(column);
+ }
+ }
- public static final String NBSP = Character.toString((char)0xa0);
+ public static final String NBSP = Character.toString((char)0xa0);
private static final String DECL_XMLNS = " xmlns=\"http://www.w3.org/1999/xhtml\"";
-
- private Location location;
- private NodeType nodeType;
- private String name;
- private Map attributes = new HashMap();
- private List childNodes = new ArrayList();
- private String content;
- public XhtmlNode() {
- super();
- }
+ private Location location;
+ private NodeType nodeType;
+ private String name;
+ private Map attributes = new HashMap();
+ private List childNodes = new ArrayList();
+ private String content;
-
- public XhtmlNode(NodeType nodeType, String name) {
- super();
- this.nodeType = nodeType;
- this.name = name;
- }
+ public XhtmlNode() {
+ super();
+ }
- public XhtmlNode(NodeType nodeType) {
- super();
- this.nodeType = nodeType;
- }
- public NodeType getNodeType() {
- return nodeType;
- }
+ public XhtmlNode(NodeType nodeType, String name) {
+ super();
+ this.nodeType = nodeType;
+ this.name = name;
+ }
- public void setNodeType(NodeType nodeType) {
- this.nodeType = nodeType;
- }
+ public XhtmlNode(NodeType nodeType) {
+ super();
+ this.nodeType = nodeType;
+ }
- public String getName() {
- return name;
- }
+ public NodeType getNodeType() {
+ return nodeType;
+ }
- public void setName(String name) {
- assert name.contains(":") == false : "Name should not contain any : but was " + name;
- this.name = name;
- }
+ public void setNodeType(NodeType nodeType) {
+ this.nodeType = nodeType;
+ }
- public Map getAttributes() {
- return attributes;
- }
+ public String getName() {
+ return name;
+ }
- public List getChildNodes() {
- return childNodes;
- }
+ public void setName(String name) {
+ assert name.contains(":") == false : "Name should not contain any : but was " + name;
+ this.name = name;
+ }
- public String getContent() {
- return content;
- }
+ public Map getAttributes() {
+ return attributes;
+ }
- public XhtmlNode setContent(String content) {
- if (!(nodeType != NodeType.Text || nodeType != NodeType.Comment))
- throw new Error("Wrong node type");
- this.content = content;
- return this;
- }
+ public List getChildNodes() {
+ return childNodes;
+ }
- public XhtmlNode addTag(String name)
- {
+ public String getContent() {
+ return content;
+ }
- if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
- throw new Error("Wrong node type. is "+nodeType.toString());
- XhtmlNode node = new XhtmlNode(NodeType.Element);
- node.setName(name);
- childNodes.add(node);
- return node;
- }
+ public XhtmlNode setContent(String content) {
+ if (!(nodeType != NodeType.Text || nodeType != NodeType.Comment))
+ throw new Error("Wrong node type");
+ this.content = content;
+ return this;
+ }
- public XhtmlNode addTag(int index, String name)
- {
+ public XhtmlNode addTag(String name)
+ {
- if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
- throw new Error("Wrong node type. is "+nodeType.toString());
- XhtmlNode node = new XhtmlNode(NodeType.Element);
- node.setName(name);
- childNodes.add(index, node);
- return node;
- }
+ if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
+ throw new Error("Wrong node type. is "+nodeType.toString());
+ XhtmlNode node = new XhtmlNode(NodeType.Element);
+ node.setName(name);
+ childNodes.add(node);
+ return node;
+ }
- public XhtmlNode addComment(String content)
- {
- if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
- throw new Error("Wrong node type");
- XhtmlNode node = new XhtmlNode(NodeType.Comment);
- node.setContent(content);
- childNodes.add(node);
- return node;
- }
+ public XhtmlNode addTag(int index, String name)
+ {
- public XhtmlNode addDocType(String content)
- {
- if (!(nodeType == NodeType.Document))
- throw new Error("Wrong node type");
- XhtmlNode node = new XhtmlNode(NodeType.DocType);
- node.setContent(content);
- childNodes.add(node);
- return node;
- }
+ if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
+ throw new Error("Wrong node type. is "+nodeType.toString());
+ XhtmlNode node = new XhtmlNode(NodeType.Element);
+ node.setName(name);
+ childNodes.add(index, node);
+ return node;
+ }
- public XhtmlNode addInstruction(String content)
- {
- if (!(nodeType == NodeType.Document))
- throw new Error("Wrong node type");
- XhtmlNode node = new XhtmlNode(NodeType.Instruction);
- node.setContent(content);
- childNodes.add(node);
- return node;
- }
+ public XhtmlNode addComment(String content)
+ {
+ if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
+ throw new Error("Wrong node type");
+ XhtmlNode node = new XhtmlNode(NodeType.Comment);
+ node.setContent(content);
+ childNodes.add(node);
+ return node;
+ }
+
+ public XhtmlNode addDocType(String content)
+ {
+ if (!(nodeType == NodeType.Document))
+ throw new Error("Wrong node type");
+ XhtmlNode node = new XhtmlNode(NodeType.DocType);
+ node.setContent(content);
+ childNodes.add(node);
+ return node;
+ }
+
+ public XhtmlNode addInstruction(String content)
+ {
+ if (!(nodeType == NodeType.Document))
+ throw new Error("Wrong node type");
+ XhtmlNode node = new XhtmlNode(NodeType.Instruction);
+ node.setContent(content);
+ childNodes.add(node);
+ return node;
+ }
- public XhtmlNode addText(String content)
- {
- if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
- throw new Error("Wrong node type");
- if (content != null) {
- XhtmlNode node = new XhtmlNode(NodeType.Text);
- node.setContent(content);
- childNodes.add(node);
- return node;
- } else
- return null;
- }
+ public XhtmlNode addText(String content)
+ {
+ if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
+ throw new Error("Wrong node type");
+ if (content != null) {
+ XhtmlNode node = new XhtmlNode(NodeType.Text);
+ node.setContent(content);
+ childNodes.add(node);
+ return node;
+ }
+ return null;
+ }
- public XhtmlNode addText(int index, String content)
- {
- if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
- throw new Error("Wrong node type");
- if (content == null)
- throw new Error("Content cannot be null");
-
- XhtmlNode node = new XhtmlNode(NodeType.Text);
- node.setContent(content);
- childNodes.add(index, node);
- return node;
- }
+ public XhtmlNode addText(int index, String content)
+ {
+ if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
+ throw new Error("Wrong node type");
+ if (content == null)
+ throw new Error("Content cannot be null");
- public boolean allChildrenAreText()
- {
- boolean res = true;
- for (XhtmlNode n : childNodes)
- res = res && n.getNodeType() == NodeType.Text;
- return res;
- }
+ XhtmlNode node = new XhtmlNode(NodeType.Text);
+ node.setContent(content);
+ childNodes.add(index, node);
+ return node;
+ }
- public XhtmlNode getElement(String name)
- {
- for (XhtmlNode n : childNodes)
- if (n.getNodeType() == NodeType.Element && name.equals(n.getName()))
- return n;
- return null;
- }
+ public boolean allChildrenAreText()
+ {
+ boolean res = true;
+ for (XhtmlNode n : childNodes)
+ res = res && n.getNodeType() == NodeType.Text;
+ return res;
+ }
- public XhtmlNode getFirstElement()
- {
- for (XhtmlNode n : childNodes)
- if (n.getNodeType() == NodeType.Element)
- return n;
- return null;
- }
+ public XhtmlNode getElement(String name)
+ {
+ for (XhtmlNode n : childNodes)
+ if (n.getNodeType() == NodeType.Element && name.equals(n.getName()))
+ return n;
+ return null;
+ }
- public String allText() {
- StringBuilder b = new StringBuilder();
- for (XhtmlNode n : childNodes)
- if (n.getNodeType() == NodeType.Text)
- b.append(n.getContent());
- else if (n.getNodeType() == NodeType.Element)
- b.append(n.allText());
- return b.toString();
- }
+ public XhtmlNode getFirstElement()
+ {
+ for (XhtmlNode n : childNodes)
+ if (n.getNodeType() == NodeType.Element)
+ return n;
+ return null;
+ }
- public XhtmlNode attribute(String name, String value) {
- if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
- throw new Error("Wrong node type");
- if (name == null)
- throw new Error("name is null");
- if (value == null)
- throw new Error("value is null");
- attributes.put(name, value);
- return this;
- }
+ public String allText() {
+ StringBuilder b = new StringBuilder();
+ for (XhtmlNode n : childNodes)
+ if (n.getNodeType() == NodeType.Text)
+ b.append(n.getContent());
+ else if (n.getNodeType() == NodeType.Element)
+ b.append(n.allText());
+ return b.toString();
+ }
- public boolean hasAttribute(String name) {
- return getAttributes().containsKey(name);
- }
+ public XhtmlNode attribute(String name, String value) {
+ if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
+ throw new Error("Wrong node type");
+ if (name == null)
+ throw new Error("name is null");
+ if (value == null)
+ throw new Error("value is null");
+ attributes.put(name, value);
+ return this;
+ }
- public String getAttribute(String name) {
- return getAttributes().get(name);
- }
+ public boolean hasAttribute(String name) {
+ return getAttributes().containsKey(name);
+ }
- public XhtmlNode setAttribute(String name, String value) {
- getAttributes().put(name, value);
- return this;
- }
-
- public XhtmlNode copy() {
- XhtmlNode dst = new XhtmlNode(nodeType);
- dst.name = name;
- for (String n : attributes.keySet()) {
- dst.attributes.put(n, attributes.get(n));
- }
- for (XhtmlNode n : childNodes)
- dst.childNodes.add(n.copy());
- dst.content = content;
- return dst;
- }
+ public String getAttribute(String name) {
+ return getAttributes().get(name);
+ }
+
+ public XhtmlNode setAttribute(String name, String value) {
+ getAttributes().put(name, value);
+ return this;
+ }
+
+ public XhtmlNode copy() {
+ XhtmlNode dst = new XhtmlNode(nodeType);
+ dst.name = name;
+ for (String n : attributes.keySet()) {
+ dst.attributes.put(n, attributes.get(n));
+ }
+ for (XhtmlNode n : childNodes)
+ dst.childNodes.add(n.copy());
+ dst.content = content;
+ return dst;
+ }
@Override
public boolean isEmpty() {
- return (childNodes == null || childNodes.isEmpty()) && content == null;
- }
+ return (childNodes == null || childNodes.isEmpty()) && content == null;
+ }
public boolean equalsDeep(XhtmlNode other) {
- if (other == null) {
- return false;
- }
+ if (other == null) {
+ return false;
+ }
- if (!(nodeType == other.nodeType) || !compare(name, other.name) || !compare(content, other.content))
- return false;
- if (attributes.size() != other.attributes.size())
- return false;
- for (String an : attributes.keySet())
- if (!attributes.get(an).equals(other.attributes.get(an)))
- return false;
- if (childNodes.size() != other.childNodes.size())
- return false;
+ if (!(nodeType == other.nodeType) || !compare(name, other.name) || !compare(content, other.content))
+ return false;
+ if (attributes.size() != other.attributes.size())
+ return false;
+ for (String an : attributes.keySet())
+ if (!attributes.get(an).equals(other.attributes.get(an)))
+ return false;
+ if (childNodes.size() != other.childNodes.size())
+ return false;
for (int i = 0; i < childNodes.size(); i++) {
if (!compareDeep(childNodes.get(i), other.childNodes.get(i)))
return false;
}
return true;
- }
+ }
private boolean compare(String s1, String s2) {
if (s1 == null && s2 == null)
@@ -331,7 +331,7 @@ public class XhtmlNode implements IBaseXhtml {
if (s1 == null || s2 == null)
return false;
return s1.equals(s2);
- }
+ }
private static boolean compareDeep(XhtmlNode e1, XhtmlNode e2) {
if (e1 == null && e2 == null)
@@ -339,18 +339,18 @@ public class XhtmlNode implements IBaseXhtml {
if (e1 == null || e2 == null)
return false;
return e1.equalsDeep(e2);
- }
-
- public String getNsDecl() {
- for (String an : attributes.keySet()) {
- if (an.equals("xmlns")) {
- return attributes.get(an);
- }
- }
- return null;
- }
-
-
+ }
+
+ public String getNsDecl() {
+ for (String an : attributes.keySet()) {
+ if (an.equals("xmlns")) {
+ return attributes.get(an);
+ }
+ }
+ return null;
+ }
+
+
@Override
public String getValueAsString() {
if (isEmpty()) {
@@ -376,9 +376,9 @@ public class XhtmlNode implements IBaseXhtml {
if (isBlank(theValue)) {
return;
}
-
+
String val = theValue.trim();
-
+
if (!val.startsWith("<")) {
val = "" + val + "
";
}
@@ -387,7 +387,7 @@ public class XhtmlNode implements IBaseXhtml {
}
val = XhtmlDt.preprocessXhtmlNamespaceDeclaration(val);
-
+
try {
// TODO: this is ugly
XhtmlNode fragment = new XhtmlParser().parseFragment(val);
@@ -400,61 +400,64 @@ public class XhtmlNode implements IBaseXhtml {
// TODO: composer shouldn't throw exception like this
throw new RuntimeException(e);
}
-
+
}
- public XhtmlNode getElementByIndex(int i) {
- int c = 0;
- for (XhtmlNode n : childNodes)
- if (n.getNodeType() == NodeType.Element) {
- if (c == i)
- return n;
- else
- c++;
- }
- return null;
- }
+ public XhtmlNode getElementByIndex(int i) {
+ int c = 0;
+ for (XhtmlNode n : childNodes)
+ if (n.getNodeType() == NodeType.Element) {
+ if (c == i){
+ return n;
+ }
+ c++;
+ }
+ return null;
+ }
-@Override
-public String getValue() {
- return getValueAsString();
-}
+ @Override
+ public String getValue() {
+ return getValueAsString();
+ }
-@Override
-public XhtmlNode setValue(String theValue) throws IllegalArgumentException {
- setValueAsString(theValue);
- return this;
-}
+ @Override
+ public XhtmlNode setValue(String theValue) throws IllegalArgumentException {
+ setValueAsString(theValue);
+ return this;
+ }
-/**
- * Returns false
- */
-public boolean hasFormatComment() {
- return false;
-}
+ /**
+ * Returns false
+ */
+ @Override
+ public boolean hasFormatComment() {
+ return false;
+ }
-/**
- * NOT SUPPORTED - Throws {@link UnsupportedOperationException}
- */
-public List getFormatCommentsPre() {
- throw new UnsupportedOperationException();
-}
+ /**
+ * NOT SUPPORTED - Throws {@link UnsupportedOperationException}
+ */
+ @Override
+ public List getFormatCommentsPre() {
+ throw new UnsupportedOperationException();
+ }
-/**
- * NOT SUPPORTED - Throws {@link UnsupportedOperationException}
- */
-public List getFormatCommentsPost() {
- throw new UnsupportedOperationException();
-}
+ /**
+ * NOT SUPPORTED - Throws {@link UnsupportedOperationException}
+ */
+ @Override
+ public List getFormatCommentsPost() {
+ throw new UnsupportedOperationException();
+ }
-public Location getLocation() {
- return location;
-}
+ public Location getLocation() {
+ return location;
+ }
-public void setLocation(Location location) {
- this.location = location;
-}
+ public void setLocation(Location location) {
+ this.location = location;
+ }
}
diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java
index 1a54dc7db73..dda22dde031 100644
--- a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java
+++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java
@@ -227,17 +227,17 @@ public class XhtmlParser {
if (validatorMode)
return true;
boolean ok = attributes.contains(attr) || attributes.contains(elem + "." + attr);
- if (ok)
+ if (ok) {
return true;
- else
- switch (policy) {
- case Accept:
- return true;
- case Drop:
- return false;
- case Reject:
- throw new FHIRFormatError("Illegal HTML attribute " + elem + "." + attr);
- }
+ }
+ switch (policy) {
+ case Accept:
+ return true;
+ case Drop:
+ return false;
+ case Reject:
+ throw new FHIRFormatError("Illegal HTML attribute " + elem + "." + attr);
+ }
if ((elem + "." + attr).equals("img.src") && !(value.startsWith("#") || value.startsWith("http:") || value.startsWith("https:"))) {
switch (policy) {
@@ -306,17 +306,17 @@ public class XhtmlParser {
if (validatorMode)
return true;
boolean ok = elements.contains(name);
- if (ok)
+ if (ok){
return true;
- else
- switch (policy) {
- case Accept:
- return true;
- case Drop:
- return false;
- case Reject:
- throw new FHIRFormatError("Illegal HTML element " + name);
- }
+ }
+ switch (policy) {
+ case Accept:
+ return true;
+ case Drop:
+ return false;
+ case Reject:
+ throw new FHIRFormatError("Illegal HTML element " + name);
+ }
return false;
}
@@ -458,26 +458,25 @@ public class XhtmlParser {
else if (peekChar() == '/') {
readChar();
QName n = new QName(readToTagEnd());
- if (node.getName().equals(n.getName()))
+ if (node.getName().equals(n.getName())){
return;
- else {
- if (mustBeWellFormed)
- throw new FHIRFormatError("Malformed XHTML: Found \"" + n.getName() + ">\" expecting \"" + node.getName() + ">\"" + descLoc());
- for (int i = parents.size() - 1; i >= 0; i--) {
- if (parents.get(i).getName().equals(n))
- unwindPoint = parents.get(i);
- }
- if (unwindPoint != null) {
- for (int i = parents.size(); i > 0; i--) {
- if (i < parents.size() && parents.get(i) == unwindPoint)
- return;
- if (i == parents.size()) {
- parents.get(i - 1).getChildNodes().addAll(node.getChildNodes());
- node.getChildNodes().clear();
- } else {
- parents.get(i - 1).getChildNodes().addAll(parents.get(i).getChildNodes());
- parents.get(i).getChildNodes().clear();
- }
+ }
+ if (mustBeWellFormed)
+ throw new FHIRFormatError("Malformed XHTML: Found \"" + n.getName() + ">\" expecting \"" + node.getName() + ">\"" + descLoc());
+ for (int i = parents.size() - 1; i >= 0; i--) {
+ if (parents.get(i).getName().equals(n))
+ unwindPoint = parents.get(i);
+ }
+ if (unwindPoint != null) {
+ for (int i = parents.size(); i > 0; i--) {
+ if (i < parents.size() && parents.get(i) == unwindPoint)
+ return;
+ if (i == parents.size()) {
+ parents.get(i - 1).getChildNodes().addAll(node.getChildNodes());
+ node.getChildNodes().clear();
+ } else {
+ parents.get(i - 1).getChildNodes().addAll(parents.get(i).getChildNodes());
+ parents.get(i).getChildNodes().clear();
}
}
}
diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java
index c943109b184..b36b8d0d704 100644
--- a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java
+++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java
@@ -275,38 +275,37 @@ public class XMLUtil {
* @return escape string
*/
public static String escapeXML(String rawContent, String charset, boolean isNoLines) {
- if (rawContent == null)
+ if (rawContent == null){
return "";
- else {
- StringBuffer sb = new StringBuffer();
+ }
+ StringBuffer sb = new StringBuffer();
- for (int i = 0; i < rawContent.length(); i++) {
- char ch = rawContent.charAt(i);
- if (ch == '\'')
- sb.append("'");
- else if (ch == '&')
- sb.append("&");
- else if (ch == '"')
- sb.append(""");
- else if (ch == '<')
- sb.append("<");
- else if (ch == '>')
- sb.append(">");
- else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
- // TODO - why is hashcode the only way to get the unicode number for the character
- // in jre 5.0?
- sb.append(""+Integer.toHexString(new Character(ch).hashCode()).toUpperCase()+";");
- else if (isNoLines) {
- if (ch == '\r')
- sb.append("
");
- else if (ch != '\n')
- sb.append(ch);
- }
- else
+ for (int i = 0; i < rawContent.length(); i++) {
+ char ch = rawContent.charAt(i);
+ if (ch == '\'')
+ sb.append("'");
+ else if (ch == '&')
+ sb.append("&");
+ else if (ch == '"')
+ sb.append(""");
+ else if (ch == '<')
+ sb.append("<");
+ else if (ch == '>')
+ sb.append(">");
+ else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
+ // TODO - why is hashcode the only way to get the unicode number for the character
+ // in jre 5.0?
+ sb.append(""+Integer.toHexString(new Character(ch).hashCode()).toUpperCase()+";");
+ else if (isNoLines) {
+ if (ch == '\r')
+ sb.append("
");
+ else if (ch != '\n')
sb.append(ch);
}
- return sb.toString();
+ else
+ sb.append(ch);
}
+ return sb.toString();
}
public static Element getFirstChild(Element e) {
@@ -435,6 +434,7 @@ public class XMLUtil {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
+ //FIXME resource leak
return builder.parse(new FileInputStream(filename));
}
diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java
index f66a0915b2c..ab739b9390d 100644
--- a/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java
+++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java
@@ -401,10 +401,10 @@ public class XMLWriter extends OutputStreamWriter implements IXMLWriter {
@Override
public String getDefaultNamespace() {
XMLNamespace ns = findDefaultNamespace();
- if (ns == null)
+ if (ns == null) {
return null;
- else
- return ns.getNamespace();
+ }
+ return ns.getNamespace();
}
/* (non-Javadoc)
@@ -519,10 +519,10 @@ public class XMLWriter extends OutputStreamWriter implements IXMLWriter {
writePendingComment();
pendingClose = false;
}
-
- if (name == null) {
- throw new IOException("name is null");
- }
+//death code
+// if (name == null) {
+// throw new IOException("name is null");
+// }
newLevelIfRequired();
levels.current().setName(name);
levels.current().setNamespace(namespace);
@@ -615,23 +615,22 @@ public class XMLWriter extends OutputStreamWriter implements IXMLWriter {
checkStarted();
if (levels.empty()) {
throw new IOException("Called exit one too many times");
+ }
+ if (pendingClose) {
+ write("/>");
+ writePendingComment();
+ pendingClose = false;
} else {
- if (pendingClose) {
- write("/>");
- writePendingComment();
- pendingClose = false;
- } else {
- if (levels.current().hasChildren())
- writePretty();
- write("");
- if (levels.current().getNamespace() == null)
- write(levels.current().getName());
- else
- write(getNSAbbreviation(levels.current().getNamespace())+levels.current().getName());
- write('>');
- }
- levels.pop();
+ if (levels.current().hasChildren())
+ writePretty();
+ write("");
+ if (levels.current().getNamespace() == null)
+ write(levels.current().getName());
+ else
+ write(getNSAbbreviation(levels.current().getNamespace())+levels.current().getName());
+ write('>');
}
+ levels.pop();
}
/* (non-Javadoc)
@@ -830,8 +829,8 @@ public class XMLWriter extends OutputStreamWriter implements IXMLWriter {
for (int i = 0; i < levels.size() - 1; i++)
write(" ");
return (levels.size() - 1) * 2;
- } else
- return 0;
+ }
+ return 0;
}
public int getLineType() {
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/json/JsonLikeStructureTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/json/JsonLikeStructureTest.java
index 925340ac1b8..bc120a0e2c6 100644
--- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/json/JsonLikeStructureTest.java
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/json/JsonLikeStructureTest.java
@@ -7,11 +7,9 @@ import java.io.StringReader;
import org.junit.Test;
-import ca.uhn.fhir.context.FhirContext;
-
public class JsonLikeStructureTest {
- private static FhirContext ourCtx;
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeStructureTest.class);
+// private static FhirContext ourCtx;
+// private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeStructureTest.class);
private static final String TEST_STRUCTURELOADING_DATA =
"{" +
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java
index f3b689e29ea..d55b7a9a1cc 100644
--- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java
@@ -1,11 +1,11 @@
package ca.uhn.fhir.util;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
-import ca.uhn.fhir.util.UrlUtil.UrlParts;
-
public class UrlUtilTest {
@Test
diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml
index f5cd1d325aa..53a0dadd33a 100644
--- a/hapi-fhir-structures-dstu2/pom.xml
+++ b/hapi-fhir-structures-dstu2/pom.xml
@@ -99,7 +99,7 @@
net.sf.json-lib
json-lib
- 2.4
+
jdk15
test
@@ -116,7 +116,7 @@
net.sf.json-lib
json-lib
- 2.4
+
jdk15-sources
test
@@ -139,7 +139,7 @@
directory-naming
naming-java
- 0.8
+
test
diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml
index c04497c465c..95a218e25ac 100644
--- a/hapi-fhir-structures-hl7org-dstu2/pom.xml
+++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml
@@ -121,7 +121,7 @@
net.sf.json-lib
json-lib
- 2.4
+
jdk15
test
@@ -142,7 +142,7 @@
net.sf.json-lib
json-lib
- 2.4
+
jdk15-sources
test
@@ -165,7 +165,7 @@
directory-naming
naming-java
- 0.8
+
test
From ef23b45d2581194cb591cca25dd3372728e63511 Mon Sep 17 00:00:00 2001
From: James
Date: Wed, 8 Feb 2017 19:17:12 -0500
Subject: [PATCH 06/20] Custom extension params working now
---
.../FhirResourceDaoSearchParameterDstu3.java | 6 ++
.../dao/dstu3/SearchParamExtractorDstu3.java | 10 ++++
.../dao/dstu3/SearchParamRegistryDstu3.java | 2 +-
...ceDaoDstu3SearchCustomSearchParamTest.java | 58 ++++++++++++++++++-
...rceProviderCustomSearchParamDstu3Test.java | 50 ++++++++++++++++
5 files changed, 122 insertions(+), 4 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSearchParameterDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSearchParameterDstu3.java
index f816fe2f6d4..c5cacbad5e1 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSearchParameterDstu3.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSearchParameterDstu3.java
@@ -34,6 +34,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import ca.uhn.fhir.jpa.dao.BaseSearchParamExtractor;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSearchParameter;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
+import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.DeleteConflict;
import ca.uhn.fhir.parser.DataFormatException;
@@ -47,6 +48,9 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3 mySystemDao;
+ @Autowired
+ private ISearchParamRegistry mySearchParamRegistry;
+
private void markAffectedResources(SearchParameter theResource) {
if (theResource != null) {
String expression = theResource.getExpression();
@@ -55,6 +59,8 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3());
}
if (activeSearchParams.containsKey(nextEntry.getKey())) {
- ourLog.info("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName);
+ ourLog.debug("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName);
}
if (nextSp != null) {
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchCustomSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchCustomSearchParamTest.java
index 501264d3476..0a66db36bed 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchCustomSearchParamTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchCustomSearchParamTest.java
@@ -1,7 +1,6 @@
package ca.uhn.fhir.jpa.dao.dstu3;
import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@@ -9,9 +8,11 @@ import static org.junit.Assert.fail;
import java.util.List;
+import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.SearchParameter;
+import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.Test;
@@ -19,7 +20,6 @@ import org.junit.Test;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
-import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
@@ -112,6 +112,58 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
}
+ @Test
+ public void testExtensionWithNoValueIndexesWithoutFailure() {
+ SearchParameter eyeColourSp = new SearchParameter();
+ eyeColourSp.setCode("eyecolour");
+ eyeColourSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
+ eyeColourSp.setTitle("Eye Colour");
+ eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
+ eyeColourSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
+ eyeColourSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
+ mySearchParameterDao.create(eyeColourSp, mySrd);
+
+ mySearchParamRegsitry.forceRefresh();
+
+ Patient p1 = new Patient();
+ p1.setActive(true);
+ p1.addExtension().setUrl("http://acme.org/eyecolour").addExtension().setUrl("http://foo").setValue(new StringType("VAL"));
+ IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
+
+ }
+
+ @Test
+ public void testSearchForExtension() {
+ SearchParameter eyeColourSp = new SearchParameter();
+ eyeColourSp.setCode("eyecolour");
+ eyeColourSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
+ eyeColourSp.setTitle("Eye Colour");
+ eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
+ eyeColourSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
+ eyeColourSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
+ mySearchParameterDao.create(eyeColourSp, mySrd);
+
+ mySearchParamRegsitry.forceRefresh();
+
+ Patient p1 = new Patient();
+ p1.setActive(true);
+ p1.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("blue"));
+ IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
+
+ Patient p2 = new Patient();
+ p2.setActive(true);
+ p2.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("green"));
+ IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
+
+ // Try with custom gender SP
+ SearchParameterMap map = new SearchParameterMap();
+ map.add("eyecolour", new TokenParam(null, "blue"));
+ IBundleProvider results = myPatientDao.search(map);
+ List foundResources = toUnqualifiedVersionlessIdValues(results);
+ assertThat(foundResources, contains(p1id.getValue()));
+
+ }
+
@Test
public void testSearchWithCustomParam() {
@@ -154,7 +206,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
// Delete the param
mySearchParameterDao.delete(spId, mySrd);
-
+
mySearchParamRegsitry.forceRefresh();
mySystemDao.performReindexingPass(100);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java
index 18e2416a292..7006efe58a9 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderCustomSearchParamDstu3Test.java
@@ -14,6 +14,7 @@ import java.util.Map;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.CapabilityStatement;
+import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent;
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
@@ -35,6 +36,7 @@ import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.rest.gclient.ReferenceClientParam;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
+import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
@@ -70,6 +72,54 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
}
}
+
+ @Test
+ public void testSearchForExtension() {
+ SearchParameter eyeColourSp = new SearchParameter();
+ eyeColourSp.setCode("eyecolour");
+ eyeColourSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
+ eyeColourSp.setTitle("Eye Colour");
+ eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
+ eyeColourSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
+ eyeColourSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
+
+ ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(eyeColourSp));
+
+ ourClient
+ .create()
+ .resource(eyeColourSp)
+ .execute();
+
+// mySearchParamRegsitry.forceRefresh();
+
+ Patient p1 = new Patient();
+ p1.setActive(true);
+ p1.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("blue"));
+ IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
+
+ ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p1));
+
+ Patient p2 = new Patient();
+ p2.setActive(true);
+ p2.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("green"));
+ IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
+
+ Bundle bundle = ourClient
+ .search()
+ .forResource(Patient.class)
+ .where(new TokenClientParam("eyecolour").exactly().code("blue"))
+ .returnBundle(Bundle.class)
+ .execute();
+
+ ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
+
+ List foundResources = toUnqualifiedVersionlessIdValues(bundle);
+ assertThat(foundResources, contains(p1id.getValue()));
+
+ }
+
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderCustomSearchParamDstu3Test.class);
+
@Override
@Before
public void beforeResetConfig() {
From 0dd6364fe583586dae8b4ccc8bee17e04aad6cb2 Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Wed, 8 Feb 2017 21:42:17 -0500
Subject: [PATCH 07/20] Improve paging in JPA server for _history operation
---
.editorconfig | 9 +++++
.../rest/method/HistoryMethodBinding.java | 7 +++-
.../fhir/rest/server/BasePagingProvider.java | 36 ++++++++++++++++++
.../uhn/fhir/rest/server/BundleProviders.java | 5 +++
.../rest/server/FifoMemoryPagingProvider.java | 28 +-------------
.../uhn/fhir/rest/server/IBundleProvider.java | 11 ++++++
.../fhir/rest/server/IResourceProvider.java | 2 +-
.../rest/server/SimpleBundleProvider.java | 5 +++
.../fhir/jpa/dao/BaseSearchParamRegistry.java | 33 +++++++++-------
.../fhir/jpa/dao/ISearchParamRegistry.java | 6 ++-
.../ca/uhn/fhir/jpa/dao/SearchBuilder.java | 5 +++
.../search/DatabaseBackedPagingProvider.java | 38 ++++++++++++-------
.../search/PersistedJpaBundleProvider.java | 16 ++------
.../dstu3/SearchParamExtractorDstu3Test.java | 5 +++
.../uhn/fhir/rest/server/SearchDstu2Test.java | 5 +++
src/changes/changes.xml | 7 ++++
16 files changed, 147 insertions(+), 71 deletions(-)
create mode 100644 .editorconfig
create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BasePagingProvider.java
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000000..2ec819d6f47
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+
+[*.java]
+charset = utf-8
+indent_style = tab
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java
index decb2c1a88d..83bcdf95bf9 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java
@@ -201,7 +201,12 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
@Override
public Integer preferredPageSize() {
- return null;
+ return resources.preferredPageSize();
+ }
+
+ @Override
+ public String getUuid() {
+ return resources.getUuid();
}
};
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BasePagingProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BasePagingProvider.java
new file mode 100644
index 00000000000..d91c97129d6
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BasePagingProvider.java
@@ -0,0 +1,36 @@
+package ca.uhn.fhir.rest.server;
+
+import org.apache.commons.lang3.Validate;
+
+public abstract class BasePagingProvider implements IPagingProvider {
+
+ private int myDefaultPageSize = 10;
+ private int myMaximumPageSize = 50;
+
+ public BasePagingProvider() {
+ super();
+ }
+
+ @Override
+ public int getDefaultPageSize() {
+ return myDefaultPageSize;
+ }
+
+ @Override
+ public int getMaximumPageSize() {
+ return myMaximumPageSize;
+ }
+
+ public BasePagingProvider setDefaultPageSize(int theDefaultPageSize) {
+ Validate.isTrue(theDefaultPageSize > 0, "size must be greater than 0");
+ myDefaultPageSize = theDefaultPageSize;
+ return this;
+ }
+
+ public BasePagingProvider setMaximumPageSize(int theMaximumPageSize) {
+ Validate.isTrue(theMaximumPageSize > 0, "size must be greater than 0");
+ myMaximumPageSize = theMaximumPageSize;
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BundleProviders.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BundleProviders.java
index 7f5b6bf462b..32027e57bde 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BundleProviders.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/BundleProviders.java
@@ -64,6 +64,11 @@ public class BundleProviders {
public Integer preferredPageSize() {
return null;
}
+
+ @Override
+ public String getUuid() {
+ return null;
+ }
};
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/FifoMemoryPagingProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/FifoMemoryPagingProvider.java
index b33612f15e1..08dbda0b015 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/FifoMemoryPagingProvider.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/FifoMemoryPagingProvider.java
@@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.server;
* 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
+ * 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,
@@ -25,11 +25,9 @@ import java.util.UUID;
import org.apache.commons.lang3.Validate;
-public class FifoMemoryPagingProvider implements IPagingProvider {
+public class FifoMemoryPagingProvider extends BasePagingProvider implements IPagingProvider {
private LinkedHashMap myBundleProviders;
- private int myDefaultPageSize=10;
- private int myMaximumPageSize=50;
private int mySize;
public FifoMemoryPagingProvider(int theSize) {
@@ -39,33 +37,11 @@ public class FifoMemoryPagingProvider implements IPagingProvider {
myBundleProviders = new LinkedHashMap(mySize);
}
- @Override
- public int getDefaultPageSize() {
- return myDefaultPageSize;
- }
-
- @Override
- public int getMaximumPageSize() {
- return myMaximumPageSize;
- }
-
@Override
public synchronized IBundleProvider retrieveResultList(String theId) {
return myBundleProviders.get(theId);
}
- public FifoMemoryPagingProvider setDefaultPageSize(int theDefaultPageSize) {
- Validate.isTrue(theDefaultPageSize > 0, "size must be greater than 0");
- myDefaultPageSize = theDefaultPageSize;
- return this;
- }
-
- public FifoMemoryPagingProvider setMaximumPageSize(int theMaximumPageSize) {
- Validate.isTrue(theMaximumPageSize > 0, "size must be greater than 0");
- myMaximumPageSize = theMaximumPageSize;
- return this;
- }
-
@Override
public synchronized String storeResultList(IBundleProvider theList) {
while (myBundleProviders.size() > mySize) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java
index c833a3b0cba..609bb164f17 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java
@@ -62,4 +62,15 @@ public interface IBundleProvider {
*/
InstantDt getPublished();
+ /**
+ * Returns the UUID associated with this search. Note that this
+ * does not need to return a non-null value unless it a
+ * {@link IPagingProvider} is being used that requires UUIDs
+ * being returned.
+ *
+ * Otherwise you may simply return {@code null}
+ *
+ */
+ public String getUuid();
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IResourceProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IResourceProvider.java
index 8d5db9d99e5..35fbf8b240e 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IResourceProvider.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IResourceProvider.java
@@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.server;
* 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
+ * 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,
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/SimpleBundleProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/SimpleBundleProvider.java
index 58e9803c3de..d457d86c972 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/SimpleBundleProvider.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/SimpleBundleProvider.java
@@ -65,5 +65,10 @@ public class SimpleBundleProvider implements IBundleProvider {
public Integer preferredPageSize() {
return null;
}
+
+ @Override
+ public String getUuid() {
+ return null;
+ }
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseSearchParamRegistry.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseSearchParamRegistry.java
index 8b2cb87df03..3e468cb16ae 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseSearchParamRegistry.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseSearchParamRegistry.java
@@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.dao;
* 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
+ * 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,
@@ -56,27 +56,41 @@ public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
// nothing by default
}
- public Map> getBuiltInSearchParams() {
+ @Override
+ public Map> getActiveSearchParams() {
return myBuiltInSearchParams;
}
@Override
- public Map getActiveSearchParams(String theResourceName) {
+ public Map getActiveSearchParams(String theResourceName) {
Validate.notBlank(theResourceName, "theResourceName must not be blank or null");
return myBuiltInSearchParams.get(theResourceName);
}
+ @Override
+ public Collection getAllSearchParams(String theResourceName) {
+ Validate.notBlank(theResourceName, "theResourceName must not be null or blank");
+
+ Map map = myBuiltInSearchParams.get(theResourceName);
+ map = ObjectUtils.defaultIfNull(map, EMPTY_SP_MAP);
+ return Collections.unmodifiableCollection(map.values());
+ }
+
+ public Map> getBuiltInSearchParams() {
+ return myBuiltInSearchParams;
+ }
+
@PostConstruct
public void postConstruct() {
- Map> resourceNameToSearchParams = new HashMap>();
+ Map> resourceNameToSearchParams = new HashMap>();
for (IFhirResourceDao> nextDao : myDaos) {
RuntimeResourceDefinition nextResDef = myCtx.getResourceDefinition(nextDao.getResourceType());
String nextResourceName = nextResDef.getName();
HashMap nameToParam = new HashMap();
resourceNameToSearchParams.put(nextResourceName, nameToParam);
-
+
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
nameToParam.put(nextSp.getName(), nextSp);
}
@@ -85,13 +99,4 @@ public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
myBuiltInSearchParams = Collections.unmodifiableMap(resourceNameToSearchParams);
}
- @Override
- public Collection getAllSearchParams(String theResourceName) {
- Validate.notBlank(theResourceName, "theResourceName must not be null or blank");
-
- Map map = myBuiltInSearchParams.get(theResourceName);
- map = ObjectUtils.defaultIfNull(map, EMPTY_SP_MAP);
- return Collections.unmodifiableCollection(map.values());
- }
-
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamRegistry.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamRegistry.java
index eea349770cd..1c3d5684a9e 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamRegistry.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamRegistry.java
@@ -27,10 +27,12 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
public interface ISearchParamRegistry {
+ void forceRefresh();
+
+ Map> getActiveSearchParams();
+
Map getActiveSearchParams(String theResourceName);
Collection getAllSearchParams(String theResourceName);
- void forceRefresh();
-
}
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 3106f9bc0b8..7cff1643bb2 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
@@ -2309,6 +2309,11 @@ public class SearchBuilder {
public int size() {
return myPids.size();
}
+
+ @Override
+ public String getUuid() {
+ return null;
+ }
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/DatabaseBackedPagingProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/DatabaseBackedPagingProvider.java
index 87c51527b57..be65fc85d33 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/DatabaseBackedPagingProvider.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/DatabaseBackedPagingProvider.java
@@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.search;
import javax.persistence.EntityManager;
+import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
@@ -30,10 +31,12 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.IDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
+import ca.uhn.fhir.rest.server.BasePagingProvider;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.IBundleProvider;
+import ca.uhn.fhir.rest.server.IPagingProvider;
-public class DatabaseBackedPagingProvider extends FifoMemoryPagingProvider {
+public class DatabaseBackedPagingProvider extends BasePagingProvider implements IPagingProvider {
@Autowired
private PlatformTransactionManager thePlatformTransactionManager;
@@ -46,29 +49,36 @@ public class DatabaseBackedPagingProvider extends FifoMemoryPagingProvider {
@Autowired
private IFhirSystemDao, ?> theDao;
+ /**
+ * Constructor
+ * @deprecated Use {@link DatabaseBackedPagingProvider} as this constructor has no purpose
+ */
+ @Deprecated
public DatabaseBackedPagingProvider(int theSize) {
- super(theSize);
+ this();
+ }
+
+ /**
+ * Constructor
+ */
+ public DatabaseBackedPagingProvider() {
+ super();
}
@Override
public synchronized IBundleProvider retrieveResultList(String theId) {
- IBundleProvider retVal = super.retrieveResultList(theId);
- if (retVal == null) {
- PersistedJpaBundleProvider provider = new PersistedJpaBundleProvider(theId, theDao);
- if (!provider.ensureSearchEntityLoaded()) {
- return null;
- }
- retVal = provider;
+ PersistedJpaBundleProvider provider = new PersistedJpaBundleProvider(theId, theDao);
+ if (!provider.ensureSearchEntityLoaded()) {
+ return null;
}
- return retVal;
+ return provider;
}
@Override
public synchronized String storeResultList(IBundleProvider theList) {
- if (theList instanceof PersistedJpaBundleProvider) {
- return ((PersistedJpaBundleProvider)theList).getSearchUuid();
- }
- return super.storeResultList(theList);
+ String uuid = theList.getUuid();
+ Validate.notNull(uuid);
+ return uuid;
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/PersistedJpaBundleProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/PersistedJpaBundleProvider.java
index f9fd48f57af..4d1c15cae53 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/PersistedJpaBundleProvider.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/PersistedJpaBundleProvider.java
@@ -19,13 +19,7 @@ package ca.uhn.fhir.jpa.search;
* limitations under the License.
* #L%
*/
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
@@ -49,11 +43,7 @@ import ca.uhn.fhir.jpa.dao.IDao;
import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
-import ca.uhn.fhir.jpa.entity.BaseHasResource;
-import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
-import ca.uhn.fhir.jpa.entity.Search;
-import ca.uhn.fhir.jpa.entity.SearchResult;
-import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
+import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.server.IBundleProvider;
@@ -220,7 +210,7 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
});
}
- public String getSearchUuid() {
+ public String getUuid() {
return myUuid;
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3Test.java
index a15ff03eede..29cf58ed87c 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3Test.java
@@ -63,6 +63,11 @@ public class SearchParamExtractorDstu3Test {
public Collection getAllSearchParams(String theResourceName) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public Map> getActiveSearchParams() {
+ throw new UnsupportedOperationException();
+ }
};
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(ourCtx, ourValidationSupport, searchParamRegistry);
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java
index 7cbf365e373..ab2c58431df 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java
@@ -575,6 +575,11 @@ public class SearchDstu2Test {
public int size() {
return 0;
}
+
+ @Override
+ public String getUuid() {
+ return null;
+ }
};
}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 27d708ed4ce..c9073484855 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -138,6 +138,13 @@
JPA server did not return an OperationOutcome in the response for
a normal delete operation.
+
+ Fix an issue in JPA server where _history results were kept in memory instead
+ of being spooled to the database as they should be. Note that as a part of this fix
+ a new method was added to
+ IBundleProvider called getUuid()
]]>. This
+ method may return null]]> in any current cases.
+
From 12e047b931e38cb744b7c66c6daa680f2a42890b Mon Sep 17 00:00:00 2001
From: James
Date: Thu, 9 Feb 2017 06:53:22 -0500
Subject: [PATCH 08/20] Fix a couple of compile issues
---
.../java/example/PagingPatientProvider.java | 5 ++++
.../rest/method/HistoryMethodBinding.java | 2 +-
.../uhn/fhir/rest/server/IBundleProvider.java | 27 ++++++++++++-------
.../rest/server/SearchHl7OrgDstu2Test.java | 5 ++++
4 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/examples/src/main/java/example/PagingPatientProvider.java b/examples/src/main/java/example/PagingPatientProvider.java
index ab398a3679a..ce70e046e76 100644
--- a/examples/src/main/java/example/PagingPatientProvider.java
+++ b/examples/src/main/java/example/PagingPatientProvider.java
@@ -60,6 +60,11 @@ public class PagingPatientProvider implements IResourceProvider {
// Typically this method just returns null
return null;
}
+
+ @Override
+ public String getUuid() {
+ return null;
+ }
};
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java
index 83bcdf95bf9..efd36d79cd7 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/HistoryMethodBinding.java
@@ -171,7 +171,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
return new IBundleProvider() {
@Override
- public InstantDt getPublished() {
+ public IPrimitiveType getPublished() {
return resources.getPublished();
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java
index 609bb164f17..71c7eae09fb 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IBundleProvider.java
@@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.server;
+import java.util.Date;
+
/*
* #%L
* HAPI FHIR - Core Library
@@ -10,7 +12,7 @@ package ca.uhn.fhir.rest.server;
* 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
+ * 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,
@@ -23,6 +25,7 @@ package ca.uhn.fhir.rest.server;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.model.primitive.InstantDt;
@@ -31,15 +34,17 @@ public interface IBundleProvider {
/**
* Load the given collection of resources by index, plus any additional resources per the
* server's processing rules (e.g. _include'd resources, OperationOutcome, etc.). For example,
- * if the method is invoked with index 0,10 the method might return 10 search results, plus an
+ * if the method is invoked with index 0,10 the method might return 10 search results, plus an
* additional 20 resources which matched a client's _include specification.
*
- * @param theFromIndex The low index (inclusive) to return
- * @param theToIndex The high index (exclusive) to return
+ * @param theFromIndex
+ * The low index (inclusive) to return
+ * @param theToIndex
+ * The high index (exclusive) to return
* @return A list of resources. The size of this list must be at least theToIndex - theFromIndex
.
*/
List getResources(int theFromIndex, int theToIndex);
-
+
/**
* Optionally may be used to signal a preferred page size to the server, e.g. because
* the implementing code recognizes that the resources which will be returned by this
@@ -50,17 +55,17 @@ public interface IBundleProvider {
* @return Returns the preferred page size or null
*/
Integer preferredPageSize();
-
+
/**
* Returns the total number of results which match the given query (exclusive of any
* _include's or OperationOutcome)
*/
int size();
-
+
/**
* Returns the instant as of which this result was valid
*/
- InstantDt getPublished();
+ IPrimitiveType getPublished();
/**
* Returns the UUID associated with this search. Note that this
@@ -68,7 +73,11 @@ public interface IBundleProvider {
* {@link IPagingProvider} is being used that requires UUIDs
* being returned.
*
- * Otherwise you may simply return {@code null}
+ * In other words, if you are using the default {@link FifoMemoryPagingProvider} in
+ * your server, it is fine for this method to simply return {@code null} since {@link FifoMemoryPagingProvider}
+ * does not use the value anyhow. On the other hand, if you are creating a custom
+ * [@code IPagingProvider} implementation you might use this method to communicate
+ * the search ID back to the provider.
*
*/
public String getUuid();
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchHl7OrgDstu2Test.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchHl7OrgDstu2Test.java
index 57be98b0552..a5170173a49 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchHl7OrgDstu2Test.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchHl7OrgDstu2Test.java
@@ -160,6 +160,11 @@ public class SearchHl7OrgDstu2Test {
public int size() {
return 0;
}
+
+ @Override
+ public String getUuid() {
+ return null;
+ }
};
}
From f1828d1ca85e385cbcc6e3bb68176d59d3ec9ded Mon Sep 17 00:00:00 2001
From: James
Date: Fri, 10 Feb 2017 11:05:59 -0500
Subject: [PATCH 09/20] Fix handling of filters on valueset expansions
---
.../dstu3/FhirResourceDaoValueSetDstu3.java | 55 +-
.../FhirResourceDaoDstu3TerminologyTest.java | 847 +++++++++++-------
hapi-fhir-structures-dstu3/.editorconfig | 5 +
.../terminologies/ValueSetExpanderSimple.java | 430 ++++-----
src/changes/changes.xml | 6 +
5 files changed, 771 insertions(+), 572 deletions(-)
create mode 100644 hapi-fhir-structures-dstu3/.editorconfig
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 0aeb03689f9..1bf09d34254 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
@@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
* 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
+ * 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,
@@ -33,6 +33,7 @@ import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
+import org.hl7.fhir.dstu3.model.IntegerType;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
@@ -82,12 +83,12 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3
return retVal;
- // ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
+ // ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
//
- // ValueSet retVal = new ValueSet();
- // retVal.getMeta().setLastUpdated(new Date());
- // retVal.setExpansion(expansion);
- // return retVal;
+ // ValueSet retVal = new ValueSet();
+ // retVal.getMeta().setLastUpdated(new Date());
+ // retVal.setExpansion(expansion);
+ // return retVal;
}
private void validateIncludes(String name, List listToValidate) {
@@ -137,11 +138,11 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3
public ValueSet expand(ValueSet source, String theFilter) {
ValueSet toExpand = new ValueSet();
-// for (UriType next : source.getCompose().getInclude()) {
-// ConceptSetComponent include = toExpand.getCompose().addInclude();
-// include.setSystem(next.getValue());
-// addFilterIfPresent(theFilter, include);
-// }
+ // for (UriType next : source.getCompose().getInclude()) {
+ // ConceptSetComponent include = toExpand.getCompose().addInclude();
+ // include.setSystem(next.getValue());
+ // addFilterIfPresent(theFilter, include);
+ // }
for (ConceptSetComponent next : source.getCompose().getInclude()) {
toExpand.getCompose().addInclude(next);
@@ -155,18 +156,41 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3
toExpand.getCompose().getExclude().addAll(source.getCompose().getExclude());
ValueSet retVal = doExpand(toExpand);
+
+ if (isNotBlank(theFilter)) {
+ applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
+ }
+
return retVal;
}
+ private void applyFilter(IntegerType theTotalElement, List theContains, String theFilter) {
+
+ for (int idx = 0; idx < theContains.size(); idx++) {
+ ValueSetExpansionContainsComponent next = theContains.get(idx);
+ if (isBlank(next.getDisplay()) || !org.apache.commons.lang3.StringUtils.containsIgnoreCase(next.getDisplay(), theFilter)) {
+ theContains.remove(idx);
+ idx--;
+ if (theTotalElement.getValue() != null) {
+ theTotalElement.setValue(theTotalElement.getValue() - 1);
+ }
+ }
+ applyFilter(theTotalElement, next.getContains(), theFilter);
+ }
+ }
+
private void addFilterIfPresent(String theFilter, ConceptSetComponent include) {
- if (isNotBlank(theFilter)) {
- include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue(theFilter);
+ if (ElementUtil.isEmpty(include.getConcept())) {
+ if (isNotBlank(theFilter)) {
+ include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue(theFilter);
+ }
}
}
@Override
- public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(IPrimitiveType theValueSetIdentifier, IIdType theId, IPrimitiveType theCode, IPrimitiveType theSystem, IPrimitiveType theDisplay, Coding theCoding,
+ public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(IPrimitiveType theValueSetIdentifier, IIdType theId, IPrimitiveType theCode,
+ IPrimitiveType theSystem, IPrimitiveType theDisplay, Coding theCoding,
CodeableConcept theCodeableConcept, RequestDetails theRequestDetails) {
List valueSetIds = Collections.emptyList();
@@ -226,7 +250,8 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3
return thePrimitive != null ? thePrimitive.getValue() : null;
}
- private ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCodeIsInContains(List contains, String theSystem, String theCode, Coding theCoding, CodeableConcept theCodeableConcept) {
+ private ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCodeIsInContains(List contains, String theSystem, String theCode,
+ Coding theCoding, CodeableConcept theCodeableConcept) {
for (ValueSetExpansionContainsComponent nextCode : contains) {
ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult result = validateCodeIsInContains(nextCode.getContains(), theSystem, theCode, theCoding, theCodeableConcept);
if (result != null) {
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 414622d3a30..06691b43a41 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
@@ -16,6 +16,7 @@ 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.ValueSetComposeComponent;
@@ -53,6 +54,9 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
+ @Autowired
+ private IHapiTerminologySvc myHapiTerminologySvc;
+
@After
public void after() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(new DaoConfig().getDeferIndexingForCodesystemsOfSize());
@@ -116,6 +120,37 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
createLocalVs(codeSystem);
}
+ private CodeSystem createExternalCsDogs() {
+ CodeSystem codeSystem = new CodeSystem();
+ codeSystem.setUrl(URL_MY_CODE_SYSTEM);
+ codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
+ IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
+
+ ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
+
+ TermCodeSystemVersion cs = new TermCodeSystemVersion();
+ cs.setResource(table);
+ cs.setResourceVersionId(table.getVersion());
+
+ TermConcept hello = new TermConcept(cs, "hello").setDisplay("Hello");
+ cs.getConcepts().add(hello);
+
+ TermConcept goodbye = new TermConcept(cs, "goodbye").setDisplay("Goodbye");
+ cs.getConcepts().add(goodbye);
+
+ TermConcept dogs = new TermConcept(cs, "dogs").setDisplay("Dogs");
+ cs.getConcepts().add(dogs);
+
+ TermConcept labrador = new TermConcept(cs, "labrador").setDisplay("Labrador");
+ dogs.addChild(labrador, RelationshipTypeEnum.ISA);
+
+ TermConcept beagle = new TermConcept(cs, "beagle").setDisplay("Beagle");
+ dogs.addChild(beagle, RelationshipTypeEnum.ISA);
+
+ myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
+ return codeSystem;
+ }
+
private void createLocalCsAndVs() {
//@formatter:off
CodeSystem codeSystem = new CodeSystem();
@@ -144,6 +179,22 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
myValueSetDao.create(valueSet, mySrd);
}
+ private void logAndValidateValueSet(ValueSet theResult) {
+ IParser parser = myFhirCtx.newXmlParser().setPrettyPrint(true);
+ String encoded = parser.encodeResourceToString(theResult);
+ ourLog.info(encoded);
+
+ FhirValidator validator = myFhirCtx.newValidator();
+ validator.setValidateAgainstStandardSchema(true);
+ validator.setValidateAgainstStandardSchematron(true);
+ ValidationResult result = validator.validateWithResult(theResult);
+
+ if (!result.isSuccessful()) {
+ ourLog.info(parser.encodeResourceToString(result.toOperationOutcome()));
+ fail(parser.encodeResourceToString(result.toOperationOutcome()));
+ }
+ }
+
@Test
public void testCodeSystemCreateDuplicateFails() {
CodeSystem codeSystem = new CodeSystem();
@@ -162,28 +213,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
}
- @Test
- public void testLookupSnomed() {
- CodeSystem codeSystem = new CodeSystem();
- codeSystem.setUrl("http://snomed.info/sct");
- codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
- IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
-
- ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
-
- TermCodeSystemVersion cs = new TermCodeSystemVersion();
- cs.setResource(table);
- cs.setResourceVersionId(table.getVersion());
- TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
- cs.getConcepts().add(parentA);
- myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct", cs);
-
- StringType code = new StringType("ParentA");
- StringType system = new StringType("http://snomed.info/sct");
- LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null, mySrd);
- assertEquals(true, outcome.isFound());
- }
-
@Test
public void testCodeSystemWithDefinedCodes() {
//@formatter:off
@@ -207,170 +236,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
- @Test
- public void testExpandWithExcludeInExternalValueSet() {
- createExternalCsAndLocalVs();
-
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
-
- ConceptSetComponent exclude = vs.getCompose().addExclude();
- exclude.setSystem(URL_MY_CODE_SYSTEM);
- exclude.addConcept().setCode("childAA");
- exclude.addConcept().setCode("childAAA");
-
- ValueSet result = myValueSetDao.expand(vs, null);
- logAndValidateValueSet(result);
-
- ArrayList codes = toCodesContains(result.getExpansion().getContains());
- assertThat(codes, containsInAnyOrder("ParentA", "ParentB", "childAB", "childAAB", "ParentC", "childBA", "childCA"));
- }
-
- private void logAndValidateValueSet(ValueSet theResult) {
- IParser parser = myFhirCtx.newXmlParser().setPrettyPrint(true);
- String encoded = parser.encodeResourceToString(theResult);
- ourLog.info(encoded);
-
- FhirValidator validator = myFhirCtx.newValidator();
- validator.setValidateAgainstStandardSchema(true);
- validator.setValidateAgainstStandardSchematron(true);
- ValidationResult result = validator.validateWithResult(theResult);
-
- if (!result.isSuccessful()) {
- ourLog.info(parser.encodeResourceToString(result.toOperationOutcome()));
- fail(parser.encodeResourceToString(result.toOperationOutcome()));
- }
- }
-
- @Test
- public void testExpandWithInvalidExclude() {
- createExternalCsAndLocalVs();
-
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
-
- /*
- * No system set on exclude
- */
- ConceptSetComponent exclude = vs.getCompose().addExclude();
- exclude.addConcept().setCode("childAA");
- exclude.addConcept().setCode("childAAA");
- try {
- myValueSetDao.expand(vs, null);
- fail();
- } catch (InvalidRequestException e) {
- assertEquals("ValueSet contains exclude criteria with no system defined", e.getMessage());
- }
- }
-
- @Test
- public void testExpandWithNoResultsInLocalValueSet1() {
- createLocalCsAndVs();
-
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
- include.addConcept().setCode("ZZZZ");
-
- try {
- myValueSetDao.expand(vs, null);
- fail();
- } catch (InvalidRequestException e) {
- assertEquals("Unable to find code 'ZZZZ' in code system http://example.com/my_code_system", e.getMessage());
- }
-
- }
-
- @Test
- public void testReindex() {
- createLocalCsAndVs();
-
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
- include.addConcept().setCode("ZZZZ");
-
- mySystemDao.markAllResourcesForReindexing();
- mySystemDao.performReindexingPass(null);
- myTermSvc.saveDeferred();
- mySystemDao.performReindexingPass(null);
- myTermSvc.saveDeferred();
-
- // Again
- mySystemDao.markAllResourcesForReindexing();
- mySystemDao.performReindexingPass(null);
- myTermSvc.saveDeferred();
- mySystemDao.performReindexingPass(null);
- myTermSvc.saveDeferred();
-
- }
-
- @Test
- public void testExpandWithNoResultsInLocalValueSet2() {
- createLocalCsAndVs();
-
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM + "AA");
- include.addConcept().setCode("A");
-
- try {
- myValueSetDao.expand(vs, null);
- fail();
- } catch (InvalidRequestException e) {
- assertEquals("unable to find code system http://example.com/my_code_systemAA", e.getMessage());
- }
- }
-
- @Test
- public void testExpandWithIsAInExternalValueSet() {
- createExternalCsAndLocalVs();
-
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
- include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
-
- ValueSet result = myValueSetDao.expand(vs, null);
- logAndValidateValueSet(result);
-
- ArrayList codes = toCodesContains(result.getExpansion().getContains());
- assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
-
- }
-
- @Autowired
- private IHapiTerminologySvc myHapiTerminologySvc;
-
- @Test
- public void testExpandWithIsAInExternalValueSetReindex() {
- BaseHapiTerminologySvc.setForceSaveDeferredAlwaysForUnitTest(true);
-
- createExternalCsAndLocalVs();
-
- mySystemDao.markAllResourcesForReindexing();
-
- mySystemDao.performReindexingPass(100);
- mySystemDao.performReindexingPass(100);
- myHapiTerminologySvc.saveDeferred();
- myHapiTerminologySvc.saveDeferred();
- myHapiTerminologySvc.saveDeferred();
-
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
- include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
-
- ValueSet result = myValueSetDao.expand(vs, null);
- logAndValidateValueSet(result);
-
- ArrayList codes = toCodesContains(result.getExpansion().getContains());
- assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
-
- }
-
@Test
public void testExpandInvalid() {
createExternalCsAndLocalVs();
@@ -390,43 +255,110 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
@Test
- public void testExpandWithSystemAndCodesInExternalValueSet() {
- createExternalCsAndLocalVs();
+ public void testExpandWithCodesAndDisplayFilterBlank() {
+ CodeSystem codeSystem = createExternalCsDogs();
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
- include.addConcept().setCode("ParentA");
- include.addConcept().setCode("childAA");
- include.addConcept().setCode("childAAA");
+ ValueSet valueSet = new ValueSet();
+ valueSet.setUrl(URL_MY_VALUE_SET);
+ valueSet.getCompose()
+ .addInclude()
+ .setSystem(codeSystem.getUrl())
+ .addConcept(new ConceptReferenceComponent().setCode("hello"))
+ .addConcept(new ConceptReferenceComponent().setCode("goodbye"));
+ valueSet.getCompose()
+ .addInclude()
+ .setSystem(codeSystem.getUrl())
+ .addFilter()
+ .setProperty("concept")
+ .setOp(FilterOperator.ISA)
+ .setValue("dogs");
+
+ myValueSetDao.create(valueSet, mySrd);
- ValueSet result = myValueSetDao.expand(vs, null);
+ ValueSet result = myValueSetDao.expand(valueSet, "");
logAndValidateValueSet(result);
+ assertEquals(4, result.getExpansion().getTotal());
ArrayList codes = toCodesContains(result.getExpansion().getContains());
- assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA"));
+ assertThat(codes, containsInAnyOrder("hello", "goodbye", "labrador", "beagle"));
- int idx = codes.indexOf("childAA");
- assertEquals("childAA", result.getExpansion().getContains().get(idx).getCode());
- assertEquals("Child AA", result.getExpansion().getContains().get(idx).getDisplay());
- assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
}
@Test
- public void testExpandWithSystemAndFilterInExternalValueSet() {
- createExternalCsAndLocalVs();
+ public void testExpandWithCodesAndDisplayFilterPartialOnFilter() {
+ CodeSystem codeSystem = createExternalCsDogs();
- ValueSet vs = new ValueSet();
- ConceptSetComponent include = vs.getCompose().addInclude();
- include.setSystem(URL_MY_CODE_SYSTEM);
+ ValueSet valueSet = new ValueSet();
+ valueSet.setUrl(URL_MY_VALUE_SET);
+ valueSet.getCompose()
+ .addInclude()
+ .setSystem(codeSystem.getUrl())
+ .addConcept(new ConceptReferenceComponent().setCode("hello"))
+ .addConcept(new ConceptReferenceComponent().setCode("goodbye"));
+ valueSet.getCompose()
+ .addInclude()
+ .setSystem(codeSystem.getUrl())
+ .addFilter()
+ .setProperty("concept")
+ .setOp(FilterOperator.ISA)
+ .setValue("dogs");
+
+ myValueSetDao.create(valueSet, mySrd);
- include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Parent B");
-
- ValueSet result = myValueSetDao.expand(vs, null);
+ ValueSet result = myValueSetDao.expand(valueSet, "lab");
logAndValidateValueSet(result);
+ assertEquals(1, result.getExpansion().getTotal());
ArrayList codes = toCodesContains(result.getExpansion().getContains());
- assertThat(codes, containsInAnyOrder("ParentB"));
+ assertThat(codes, containsInAnyOrder("labrador"));
+
+ }
+
+ @Test
+ public void testExpandWithCodesAndDisplayFilterPartialOnCodes() {
+ CodeSystem codeSystem = createExternalCsDogs();
+
+ ValueSet valueSet = new ValueSet();
+ valueSet.setUrl(URL_MY_VALUE_SET);
+ valueSet.getCompose()
+ .addInclude()
+ .setSystem(codeSystem.getUrl())
+ .addConcept(new ConceptReferenceComponent().setCode("hello"))
+ .addConcept(new ConceptReferenceComponent().setCode("goodbye"));
+ valueSet.getCompose()
+ .addInclude()
+ .setSystem(codeSystem.getUrl())
+ .addFilter()
+ .setProperty("concept")
+ .setOp(FilterOperator.ISA)
+ .setValue("dogs");
+
+ myValueSetDao.create(valueSet, mySrd);
+
+ ValueSet result = myValueSetDao.expand(valueSet, "hel");
+ logAndValidateValueSet(result);
+
+ assertEquals(1, result.getExpansion().getTotal());
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("hello"));
+
+ }
+
+ @Test
+ public void testExpandWithCodesAndDisplayFilterPartialOnExpansion() {
+ CodeSystem codeSystem = createExternalCsDogs();
+
+ ValueSet valueSet = new ValueSet();
+ valueSet.setUrl(URL_MY_VALUE_SET);
+ valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
+ myValueSetDao.create(valueSet, mySrd);
+
+ ValueSet result = myValueSetDao.expand(valueSet, "lab");
+ logAndValidateValueSet(result);
+
+ assertEquals(1, result.getExpansion().getTotal());
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("labrador"));
}
@@ -463,6 +395,127 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
+ @Test
+ public void testExpandWithExcludeInExternalValueSet() {
+ createExternalCsAndLocalVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+
+ ConceptSetComponent exclude = vs.getCompose().addExclude();
+ exclude.setSystem(URL_MY_CODE_SYSTEM);
+ exclude.addConcept().setCode("childAA");
+ exclude.addConcept().setCode("childAAA");
+
+ ValueSet result = myValueSetDao.expand(vs, null);
+ logAndValidateValueSet(result);
+
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("ParentA", "ParentB", "childAB", "childAAB", "ParentC", "childBA", "childCA"));
+ }
+
+ @Test
+ public void testExpandWithInvalidExclude() {
+ createExternalCsAndLocalVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+
+ /*
+ * No system set on exclude
+ */
+ ConceptSetComponent exclude = vs.getCompose().addExclude();
+ exclude.addConcept().setCode("childAA");
+ exclude.addConcept().setCode("childAAA");
+ try {
+ myValueSetDao.expand(vs, null);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertEquals("ValueSet contains exclude criteria with no system defined", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testExpandWithIsAInExternalValueSet() {
+ createExternalCsAndLocalVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+ include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
+
+ ValueSet result = myValueSetDao.expand(vs, null);
+ logAndValidateValueSet(result);
+
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
+
+ }
+
+ @Test
+ public void testExpandWithIsAInExternalValueSetReindex() {
+ BaseHapiTerminologySvc.setForceSaveDeferredAlwaysForUnitTest(true);
+
+ createExternalCsAndLocalVs();
+
+ mySystemDao.markAllResourcesForReindexing();
+
+ mySystemDao.performReindexingPass(100);
+ mySystemDao.performReindexingPass(100);
+ myHapiTerminologySvc.saveDeferred();
+ myHapiTerminologySvc.saveDeferred();
+ myHapiTerminologySvc.saveDeferred();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+ include.addFilter().setOp(FilterOperator.ISA).setValue("childAA").setProperty("concept");
+
+ ValueSet result = myValueSetDao.expand(vs, null);
+ logAndValidateValueSet(result);
+
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
+
+ }
+
+ @Test
+ public void testExpandWithNoResultsInLocalValueSet1() {
+ createLocalCsAndVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+ include.addConcept().setCode("ZZZZ");
+
+ try {
+ myValueSetDao.expand(vs, null);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertEquals("Unable to find code 'ZZZZ' in code system http://example.com/my_code_system", e.getMessage());
+ }
+
+ }
+
+ @Test
+ public void testExpandWithNoResultsInLocalValueSet2() {
+ createLocalCsAndVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM + "AA");
+ include.addConcept().setCode("A");
+
+ try {
+ myValueSetDao.expand(vs, null);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertEquals("unable to find code system http://example.com/my_code_systemAA", e.getMessage());
+ }
+ }
+
@Test
public void testExpandWithSystemAndCodesAndFilterKeywordInLocalValueSet() {
createLocalCsAndVs();
@@ -493,6 +546,29 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
//
}
+ @Test
+ public void testExpandWithSystemAndCodesInExternalValueSet() {
+ createExternalCsAndLocalVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+ include.addConcept().setCode("ParentA");
+ include.addConcept().setCode("childAA");
+ include.addConcept().setCode("childAAA");
+
+ ValueSet result = myValueSetDao.expand(vs, null);
+ logAndValidateValueSet(result);
+
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA"));
+
+ int idx = codes.indexOf("childAA");
+ assertEquals("childAA", result.getExpansion().getContains().get(idx).getCode());
+ assertEquals("Child AA", result.getExpansion().getContains().get(idx).getDisplay());
+ assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
+ }
+
@Test
public void testExpandWithSystemAndCodesInLocalValueSet() {
createLocalCsAndVs();
@@ -520,6 +596,43 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
//
}
+ @Test
+ public void testExpandWithSystemAndDisplayFilterBlank() {
+ CodeSystem codeSystem = createExternalCsDogs();
+
+ ValueSet valueSet = new ValueSet();
+ valueSet.setUrl(URL_MY_VALUE_SET);
+ valueSet.getCompose()
+ .addInclude()
+ .setSystem(codeSystem.getUrl());
+
+ ValueSet result = myValueSetDao.expand(valueSet, "");
+ logAndValidateValueSet(result);
+
+ assertEquals(5, result.getExpansion().getTotal());
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("hello", "goodbye", "dogs", "labrador", "beagle"));
+
+ }
+
+ @Test
+ public void testExpandWithSystemAndFilterInExternalValueSet() {
+ createExternalCsAndLocalVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+
+ include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Parent B");
+
+ ValueSet result = myValueSetDao.expand(vs, null);
+ logAndValidateValueSet(result);
+
+ ArrayList codes = toCodesContains(result.getExpansion().getContains());
+ assertThat(codes, containsInAnyOrder("ParentB"));
+
+ }
+
@Test
public void testIndexingIsDeferredForLargeCodeSystems() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(1);
@@ -560,6 +673,28 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
assertThat(encoded, containsStringIgnoringCase(""));
}
+ @Test
+ public void testLookupSnomed() {
+ CodeSystem codeSystem = new CodeSystem();
+ codeSystem.setUrl("http://snomed.info/sct");
+ codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
+ IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
+
+ ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
+
+ TermCodeSystemVersion cs = new TermCodeSystemVersion();
+ cs.setResource(table);
+ cs.setResourceVersionId(table.getVersion());
+ TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
+ cs.getConcepts().add(parentA);
+ myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct", cs);
+
+ StringType code = new StringType("ParentA");
+ StringType system = new StringType("http://snomed.info/sct");
+ LookupCodeResult outcome = myCodeSystemDao.lookupCode(code, system, null, mySrd);
+ assertEquals(true, outcome.isFound());
+ }
+
/**
* Can't currently abort costly
*/
@@ -594,6 +729,30 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
}
+ @Test
+ public void testReindex() {
+ createLocalCsAndVs();
+
+ ValueSet vs = new ValueSet();
+ ConceptSetComponent include = vs.getCompose().addInclude();
+ include.setSystem(URL_MY_CODE_SYSTEM);
+ include.addConcept().setCode("ZZZZ");
+
+ mySystemDao.markAllResourcesForReindexing();
+ mySystemDao.performReindexingPass(null);
+ myTermSvc.saveDeferred();
+ mySystemDao.performReindexingPass(null);
+ myTermSvc.saveDeferred();
+
+ // Again
+ mySystemDao.markAllResourcesForReindexing();
+ mySystemDao.performReindexingPass(null);
+ myTermSvc.saveDeferred();
+ mySystemDao.performReindexingPass(null);
+ myTermSvc.saveDeferred();
+
+ }
+
@Test
public void testSearchCodeAboveLocalCodesystem() {
createLocalCsAndVs();
@@ -636,107 +795,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
- @Test
- public void testSearchCodeBelowLocalCodesystem() {
- createLocalCsAndVs();
-
- Observation obsAA = new Observation();
- obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
- IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
-
- Observation obsBA = new Observation();
- obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
- IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
-
- Observation obsCA = new Observation();
- obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
- IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
-
- SearchParameterMap params = new SearchParameterMap();
- params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.BELOW));
- assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
-
- params = new SearchParameterMap();
- params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.BELOW));
- assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
-
- }
-
- @Test
- public void testSearchCodeInBuiltInValueSet() {
- AllergyIntolerance ai1 = new AllergyIntolerance();
- ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
- String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
-
- AllergyIntolerance ai2 = new AllergyIntolerance();
- ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
- String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
-
- AllergyIntolerance ai3 = new AllergyIntolerance();
- ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
- String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
-
- SearchParameterMap params;
- params = new SearchParameterMap();
- params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-clinical-status").setModifier(TokenParamModifier.IN));
- assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
-
- // No codes in this one
- params = new SearchParameterMap();
- params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.IN));
- assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
-
- // Invalid VS
- params = new SearchParameterMap();
- params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.IN));
- try {
- myAllergyIntoleranceDao.search(params);
- } catch (InvalidRequestException e) {
- assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
- }
-
- }
-
-
- /**
- * Todo: not yet implemented
- */
- @Test
- @Ignore
- public void testSearchCodeNotInBuiltInValueSet() {
- AllergyIntolerance ai1 = new AllergyIntolerance();
- ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
- String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
-
- AllergyIntolerance ai2 = new AllergyIntolerance();
- ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
- String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
-
- AllergyIntolerance ai3 = new AllergyIntolerance();
- ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
- String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
-
- SearchParameterMap params;
- params = new SearchParameterMap();
- params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-status").setModifier(TokenParamModifier.NOT_IN));
- assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
-
- // No codes in this one
- params = new SearchParameterMap();
- params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.NOT_IN));
- assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
-
- // Invalid VS
- params = new SearchParameterMap();
- params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.NOT_IN));
- try {
- myAllergyIntoleranceDao.search(params);
- } catch (InvalidRequestException e) {
- assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
- }
-
- }
-
@Test
public void testSearchCodeBelowBuiltInCodesystem() {
AllergyIntolerance ai1 = new AllergyIntolerance();
@@ -824,6 +882,68 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
+
+ @Test
+ public void testSearchCodeBelowLocalCodesystem() {
+ createLocalCsAndVs();
+
+ Observation obsAA = new Observation();
+ obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
+ IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
+
+ Observation obsBA = new Observation();
+ obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
+ IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
+
+ Observation obsCA = new Observation();
+ obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
+ IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
+
+ SearchParameterMap params = new SearchParameterMap();
+ params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.BELOW));
+ assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
+
+ params = new SearchParameterMap();
+ params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.BELOW));
+ assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
+
+ }
+
+ @Test
+ public void testSearchCodeInBuiltInValueSet() {
+ AllergyIntolerance ai1 = new AllergyIntolerance();
+ ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
+ String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
+
+ AllergyIntolerance ai2 = new AllergyIntolerance();
+ ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
+ String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
+
+ AllergyIntolerance ai3 = new AllergyIntolerance();
+ ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
+ String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
+
+ SearchParameterMap params;
+ params = new SearchParameterMap();
+ params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-clinical-status").setModifier(TokenParamModifier.IN));
+ assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
+
+ // No codes in this one
+ params = new SearchParameterMap();
+ params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.IN));
+ assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
+
+ // Invalid VS
+ params = new SearchParameterMap();
+ params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.IN));
+ try {
+ myAllergyIntoleranceDao.search(params);
+ } catch (InvalidRequestException e) {
+ assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
+ }
+
+ }
+
@Test
public void testSearchCodeInEmptyValueSet() {
ValueSet valueSet = new ValueSet();
@@ -848,40 +968,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
ourLog.info("testSearchCodeInEmptyValueSet done");
}
- @Test
- public void testSearchCodeInValueSetThatImportsInvalidCodeSystem() {
- ValueSet valueSet = new ValueSet();
- valueSet.getCompose().addInclude().addValueSet("http://non_existant_VS");
- valueSet.setUrl(URL_MY_VALUE_SET);
- IIdType vsid = myValueSetDao.create(valueSet, mySrd).getId().toUnqualifiedVersionless();
-
- SearchParameterMap params;
-
- ourLog.info("testSearchCodeInEmptyValueSet without status");
-
- params = new SearchParameterMap();
- params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
- try {
- myObservationDao.search(params);
- } catch(InvalidRequestException e) {
- assertEquals("Unable to expand imported value set: Unable to find imported value set http://non_existant_VS", e.getMessage());
- }
-
- // Now let's update
- valueSet = new ValueSet();
- valueSet.setId(vsid);
- valueSet.getCompose().addInclude().setSystem("http://hl7.org/fhir/v3/MaritalStatus").addConcept().setCode("A");
- valueSet.setUrl(URL_MY_VALUE_SET);
- myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
-
- params = new SearchParameterMap();
- params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
- params.add(Observation.SP_STATUS, new TokenParam(null, "final"));
- assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
-
- }
-
-
@Test
public void testSearchCodeInExternalCodesystem() {
createExternalCsAndLocalVs();
@@ -941,6 +1027,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
assertThat(toUnqualifiedVersionlessIdValues(myAuditEventDao.search(params)), empty());
}
+
@Test
public void testSearchCodeInLocalCodesystem() {
createLocalCsAndVs();
@@ -963,6 +1050,78 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
+ @Test
+ public void testSearchCodeInValueSetThatImportsInvalidCodeSystem() {
+ ValueSet valueSet = new ValueSet();
+ valueSet.getCompose().addInclude().addValueSet("http://non_existant_VS");
+ valueSet.setUrl(URL_MY_VALUE_SET);
+ IIdType vsid = myValueSetDao.create(valueSet, mySrd).getId().toUnqualifiedVersionless();
+
+ SearchParameterMap params;
+
+ ourLog.info("testSearchCodeInEmptyValueSet without status");
+
+ params = new SearchParameterMap();
+ params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
+ try {
+ myObservationDao.search(params);
+ } catch(InvalidRequestException e) {
+ assertEquals("Unable to expand imported value set: Unable to find imported value set http://non_existant_VS", e.getMessage());
+ }
+
+ // Now let's update
+ valueSet = new ValueSet();
+ valueSet.setId(vsid);
+ valueSet.getCompose().addInclude().setSystem("http://hl7.org/fhir/v3/MaritalStatus").addConcept().setCode("A");
+ valueSet.setUrl(URL_MY_VALUE_SET);
+ myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
+
+ params = new SearchParameterMap();
+ params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
+ params.add(Observation.SP_STATUS, new TokenParam(null, "final"));
+ assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
+
+ }
+
+ /**
+ * Todo: not yet implemented
+ */
+ @Test
+ @Ignore
+ public void testSearchCodeNotInBuiltInValueSet() {
+ AllergyIntolerance ai1 = new AllergyIntolerance();
+ ai1.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
+ String id1 = myAllergyIntoleranceDao.create(ai1, mySrd).getId().toUnqualifiedVersionless().getValue();
+
+ AllergyIntolerance ai2 = new AllergyIntolerance();
+ ai2.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
+ String id2 = myAllergyIntoleranceDao.create(ai2, mySrd).getId().toUnqualifiedVersionless().getValue();
+
+ AllergyIntolerance ai3 = new AllergyIntolerance();
+ ai3.setClinicalStatus(AllergyIntoleranceClinicalStatus.INACTIVE);
+ String id3 = myAllergyIntoleranceDao.create(ai3, mySrd).getId().toUnqualifiedVersionless().getValue();
+
+ SearchParameterMap params;
+ params = new SearchParameterMap();
+ params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-status").setModifier(TokenParamModifier.NOT_IN));
+ assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), empty());
+
+ // No codes in this one
+ params = new SearchParameterMap();
+ params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/allergy-intolerance-criticality").setModifier(TokenParamModifier.NOT_IN));
+ assertThat(toUnqualifiedVersionlessIdValues(myAllergyIntoleranceDao.search(params)), containsInAnyOrder(id1, id2, id3));
+
+ // Invalid VS
+ params = new SearchParameterMap();
+ params.add(AllergyIntolerance.SP_CLINICAL_STATUS, new TokenParam(null, "http://hl7.org/fhir/ValueSet/FOO").setModifier(TokenParamModifier.NOT_IN));
+ try {
+ myAllergyIntoleranceDao.search(params);
+ } catch (InvalidRequestException e) {
+ assertEquals("Unable to find imported value set http://hl7.org/fhir/ValueSet/FOO", e.getMessage());
+ }
+
+ }
+
private ArrayList toCodesContains(List theContains) {
ArrayList retVal = new ArrayList();
for (ValueSetExpansionContainsComponent next : theContains) {
diff --git a/hapi-fhir-structures-dstu3/.editorconfig b/hapi-fhir-structures-dstu3/.editorconfig
new file mode 100644
index 00000000000..cd68918bc8b
--- /dev/null
+++ b/hapi-fhir-structures-dstu3/.editorconfig
@@ -0,0 +1,5 @@
+[*.java]
+charset = utf-8
+indent_style = space
+indent_size = 2
+
diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/terminologies/ValueSetExpanderSimple.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/terminologies/ValueSetExpanderSimple.java
index b7217351356..40b74e810e2 100644
--- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/terminologies/ValueSetExpanderSimple.java
+++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/terminologies/ValueSetExpanderSimple.java
@@ -6,33 +6,33 @@ import java.io.FileNotFoundException;
import java.io.IOException;
/*
-Copyright (c) 2011+, HL7, Inc
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of HL7 nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-*/
+ * Copyright (c) 2011+, HL7, Inc
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of HL7 nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
import java.util.ArrayList;
import java.util.HashMap;
@@ -72,66 +72,67 @@ import org.hl7.fhir.utilities.Utilities;
public class ValueSetExpanderSimple implements ValueSetExpander {
- private List codes = new ArrayList();
+ private List codes = new ArrayList();
private List roots = new ArrayList();
private Map map = new HashMap();
- private IWorkerContext context;
+ private IWorkerContext context;
private boolean canBeHeirarchy = true;
- private Set excludeKeys = new HashSet();
+ private Set