More work on tester
This commit is contained in:
parent
0a7f7d0390
commit
a2a1035003
|
@ -71,6 +71,15 @@
|
||||||
<action type="fix">
|
<action type="fix">
|
||||||
Server now automatically compresses responses if the client indicates support
|
Server now automatically compresses responses if the client indicates support
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
Server failed to support optional parameters when type is String and :exact qualifier is used
|
||||||
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
Read method in client correctly populated resource ID in returned object
|
||||||
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
Support added for deleted-entry by/name, by/email, and comment from Tombstones spec
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
</body>
|
</body>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -58,13 +58,12 @@ public class Bundle extends BaseBundle /* implements IElement */{
|
||||||
private IntegerDt myTotalResults;
|
private IntegerDt myTotalResults;
|
||||||
private InstantDt myUpdated;
|
private InstantDt myUpdated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this bundle contains zero entries
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
//@formatter:off
|
return getEntries().isEmpty();
|
||||||
return super.isEmpty() &&
|
|
||||||
ElementUtil.isEmpty(myBundleId, myLinkBase, myLinkFirst, myLinkLast, myLinkNext, myLinkPrevious, myLinkSelf, myPublished, myTitle, myTotalResults) &&
|
|
||||||
ElementUtil.isEmpty(myEntries);
|
|
||||||
//@formatter:on
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -38,6 +38,9 @@ public class BundleEntry extends BaseBundle {
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
private TagList myCategories;
|
private TagList myCategories;
|
||||||
private InstantDt myDeletedAt;
|
private InstantDt myDeletedAt;
|
||||||
|
private StringDt myDeletedByEmail;
|
||||||
|
private StringDt myDeletedByName;
|
||||||
|
private StringDt myDeletedComment;
|
||||||
private StringDt myLinkAlternate;
|
private StringDt myLinkAlternate;
|
||||||
private StringDt myLinkSelf;
|
private StringDt myLinkSelf;
|
||||||
private InstantDt myPublished;
|
private InstantDt myPublished;
|
||||||
|
@ -52,18 +55,6 @@ public class BundleEntry extends BaseBundle {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
|
||||||
if (getResource() != null) {
|
|
||||||
b.append("type", getResource().getClass().getSimpleName());
|
|
||||||
} else {
|
|
||||||
b.append("No resource");
|
|
||||||
}
|
|
||||||
b.append("id", getId());
|
|
||||||
return b.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addCategory(Tag theTag) {
|
public void addCategory(Tag theTag) {
|
||||||
getCategories().add(theTag);
|
getCategories().add(theTag);
|
||||||
}
|
}
|
||||||
|
@ -85,6 +76,27 @@ public class BundleEntry extends BaseBundle {
|
||||||
return myDeletedAt;
|
return myDeletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StringDt getDeletedByEmail() {
|
||||||
|
if (myDeletedByEmail == null) {
|
||||||
|
myDeletedByEmail = new StringDt();
|
||||||
|
}
|
||||||
|
return myDeletedByEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringDt getDeletedByName() {
|
||||||
|
if (myDeletedByName == null) {
|
||||||
|
myDeletedByName = new StringDt();
|
||||||
|
}
|
||||||
|
return myDeletedByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringDt getDeletedComment() {
|
||||||
|
if (myDeletedComment == null) {
|
||||||
|
myDeletedComment = new StringDt();
|
||||||
|
}
|
||||||
|
return myDeletedComment;
|
||||||
|
}
|
||||||
|
|
||||||
public StringDt getLinkAlternate() {
|
public StringDt getLinkAlternate() {
|
||||||
if (myLinkAlternate == null) {
|
if (myLinkAlternate == null) {
|
||||||
myLinkAlternate = new StringDt();
|
myLinkAlternate = new StringDt();
|
||||||
|
@ -135,7 +147,7 @@ public class BundleEntry extends BaseBundle {
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
return super.isEmpty() &&
|
return super.isEmpty() &&
|
||||||
ElementUtil.isEmpty(myCategories, myDeletedAt, myLinkAlternate, myLinkSelf, myPublished, myResource, mySummary, myTitle, myUpdated);
|
ElementUtil.isEmpty(myCategories, myDeletedAt, myLinkAlternate, myLinkSelf, myPublished, myResource, mySummary, myTitle, myUpdated, myDeletedByEmail, myDeletedByName, myDeletedComment);
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +158,21 @@ public class BundleEntry extends BaseBundle {
|
||||||
myDeletedAt = theDeletedAt;
|
myDeletedAt = theDeletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDeletedByEmail(StringDt theDeletedByEmail) {
|
||||||
|
myDeletedByEmail = theDeletedByEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeletedByName(StringDt theDeletedByName) {
|
||||||
|
if (myDeletedByName == null) {
|
||||||
|
myDeletedByName = new StringDt();
|
||||||
|
}
|
||||||
|
myDeletedByName = theDeletedByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeletedComment(StringDt theDeletedComment) {
|
||||||
|
myDeletedComment = theDeletedComment;
|
||||||
|
}
|
||||||
|
|
||||||
public void setLinkAlternate(StringDt theLinkAlternate) {
|
public void setLinkAlternate(StringDt theLinkAlternate) {
|
||||||
myLinkAlternate = theLinkAlternate;
|
myLinkAlternate = theLinkAlternate;
|
||||||
}
|
}
|
||||||
|
@ -171,4 +198,16 @@ public class BundleEntry extends BaseBundle {
|
||||||
myUpdated = theUpdated;
|
myUpdated = theUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||||
|
if (getResource() != null) {
|
||||||
|
b.append("type", getResource().getClass().getSimpleName());
|
||||||
|
} else {
|
||||||
|
b.append("No resource");
|
||||||
|
}
|
||||||
|
b.append("id", getId());
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -525,10 +525,14 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
|
||||||
|
|
||||||
final IStandardExpression expression = expressionParser.parseExpression(configuration, theArguments, attributeValue);
|
final IStandardExpression expression = expressionParser.parseExpression(configuration, theArguments, attributeValue);
|
||||||
final Object value = expression.execute(configuration, theArguments);
|
final Object value = expression.execute(configuration, theArguments);
|
||||||
|
|
||||||
theElement.removeAttribute(theAttributeName);
|
theElement.removeAttribute(theAttributeName);
|
||||||
theElement.clearChildren();
|
theElement.clearChildren();
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
return ProcessorResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
Context context = new Context();
|
Context context = new Context();
|
||||||
context.setVariable("resource", value);
|
context.setVariable("resource", value);
|
||||||
|
|
||||||
|
|
|
@ -157,8 +157,7 @@ class ParserState<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked after any new XML event is individually processed, containing a copy of the XML event. This is basically
|
* Invoked after any new XML event is individually processed, containing a copy of the XML event. This is basically intended for embedded XHTML content
|
||||||
* intended for embedded XHTML content
|
|
||||||
*/
|
*/
|
||||||
public void xmlEvent(XMLEvent theNextEvent) {
|
public void xmlEvent(XMLEvent theNextEvent) {
|
||||||
myState.xmlEvent(theNextEvent);
|
myState.xmlEvent(theNextEvent);
|
||||||
|
@ -238,8 +237,7 @@ class ParserState<T> {
|
||||||
myInstance.setScheme(theValue);
|
myInstance.setScheme(theValue);
|
||||||
} else if ("value".equals(theName)) {
|
} else if ("value".equals(theName)) {
|
||||||
/*
|
/*
|
||||||
* This handles XML parsing, which is odd for this quasi-resource type, since the tag has three values
|
* This handles XML parsing, which is odd for this quasi-resource type, since the tag has three values instead of one like everything else.
|
||||||
* instead of one like everything else.
|
|
||||||
*/
|
*/
|
||||||
switch (myCatState) {
|
switch (myCatState) {
|
||||||
case STATE_LABEL:
|
case STATE_LABEL:
|
||||||
|
@ -299,6 +297,23 @@ class ParserState<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||||
|
if ("by".equals(theLocalPart) && verifyNamespace(XmlParser.TOMBSTONES_NS, theNamespaceURI)) {
|
||||||
|
push(new AtomDeletedEntryByState(getEntry()));
|
||||||
|
} else if ("comment".equals(theLocalPart)) {
|
||||||
|
push(new AtomPrimitiveState(getEntry().getDeletedComment()));
|
||||||
|
} else if ("link".equals(theLocalPart)) {
|
||||||
|
push(new AtomLinkState(getEntry()));
|
||||||
|
} else {
|
||||||
|
if (theNamespaceURI != null) {
|
||||||
|
throw new DataFormatException("Unexpected element: {" + theNamespaceURI + "}" + theLocalPart);
|
||||||
|
} else {
|
||||||
|
throw new DataFormatException("Unexpected element: " + theLocalPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endingElement() throws DataFormatException {
|
public void endingElement() throws DataFormatException {
|
||||||
putPlacerResourceInDeletedEntry(getEntry());
|
putPlacerResourceInDeletedEntry(getEntry());
|
||||||
|
@ -307,6 +322,33 @@ class ParserState<T> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class AtomDeletedEntryByState extends BaseState {
|
||||||
|
|
||||||
|
private BundleEntry myEntry;
|
||||||
|
|
||||||
|
public AtomDeletedEntryByState(BundleEntry theEntry) {
|
||||||
|
super(null);
|
||||||
|
myEntry = theEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||||
|
if ("name".equals(theLocalPart)) {
|
||||||
|
push(new AtomPrimitiveState(myEntry.getDeletedByName()));
|
||||||
|
} else if ("email".equals(theLocalPart)) {
|
||||||
|
push(new AtomPrimitiveState(myEntry.getDeletedByEmail()));
|
||||||
|
} else {
|
||||||
|
throw new DataFormatException("Unexpected element in entry: " + theLocalPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endingElement() throws DataFormatException {
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private class AtomDeletedJsonWhenState extends BaseState {
|
private class AtomDeletedJsonWhenState extends BaseState {
|
||||||
|
|
||||||
private String myData;
|
private String myData;
|
||||||
|
|
|
@ -143,13 +143,32 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (BundleEntry nextEntry : theBundle.getEntries()) {
|
for (BundleEntry nextEntry : theBundle.getEntries()) {
|
||||||
boolean deleted=false;
|
boolean deleted = false;
|
||||||
if (nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty()==false) {
|
if (nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false) {
|
||||||
deleted=true;
|
deleted = true;
|
||||||
eventWriter.writeStartElement("at","deleted-entry",TOMBSTONES_NS);
|
eventWriter.writeStartElement("at", "deleted-entry", TOMBSTONES_NS);
|
||||||
eventWriter.writeNamespace("at", TOMBSTONES_NS);
|
eventWriter.writeNamespace("at", TOMBSTONES_NS);
|
||||||
eventWriter.writeAttribute("ref", nextEntry.getId().getValueAsString());
|
eventWriter.writeAttribute("ref", nextEntry.getId().getValueAsString());
|
||||||
eventWriter.writeAttribute("when", nextEntry.getDeletedAt().getValueAsString());
|
eventWriter.writeAttribute("when", nextEntry.getDeletedAt().getValueAsString());
|
||||||
|
if (nextEntry.getDeletedByEmail().isEmpty() == false || nextEntry.getDeletedByName().isEmpty()) {
|
||||||
|
eventWriter.writeStartElement(TOMBSTONES_NS, "by");
|
||||||
|
if (nextEntry.getDeletedByName().isEmpty()==false) {
|
||||||
|
eventWriter.writeStartElement(TOMBSTONES_NS, "name");
|
||||||
|
eventWriter.writeCharacters(nextEntry.getDeletedByName().getValue());
|
||||||
|
eventWriter.writeEndElement();
|
||||||
|
}
|
||||||
|
if (nextEntry.getDeletedByEmail().isEmpty() == false) {
|
||||||
|
eventWriter.writeStartElement(TOMBSTONES_NS, "email");
|
||||||
|
eventWriter.writeCharacters(nextEntry.getDeletedByEmail().getValue());
|
||||||
|
eventWriter.writeEndElement();
|
||||||
|
}
|
||||||
|
eventWriter.writeEndElement();
|
||||||
|
}
|
||||||
|
if (nextEntry.getDeletedComment().isEmpty()==false) {
|
||||||
|
eventWriter.writeStartElement(TOMBSTONES_NS, "comment");
|
||||||
|
eventWriter.writeCharacters(nextEntry.getDeletedComment().getValue());
|
||||||
|
eventWriter.writeEndElement();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
eventWriter.writeStartElement("entry");
|
eventWriter.writeStartElement("entry");
|
||||||
}
|
}
|
||||||
|
@ -377,8 +396,8 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, XMLStreamWriter theEventWriter, IElement nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl, boolean theIncludedResource)
|
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, XMLStreamWriter theEventWriter, IElement nextValue, String childName,
|
||||||
throws XMLStreamException, DataFormatException {
|
BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
||||||
if (nextValue.isEmpty()) {
|
if (nextValue.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -442,8 +461,8 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> children, boolean theIncludedResource)
|
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, XMLStreamWriter theEventWriter,
|
||||||
throws XMLStreamException, DataFormatException {
|
List<? extends BaseRuntimeChildDefinition> children, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
||||||
for (BaseRuntimeChildDefinition nextChild : children) {
|
for (BaseRuntimeChildDefinition nextChild : children) {
|
||||||
if (nextChild instanceof RuntimeChildNarrativeDefinition && !theIncludedResource) {
|
if (nextChild instanceof RuntimeChildNarrativeDefinition && !theIncludedResource) {
|
||||||
INarrativeGenerator gen = myContext.getNarrativeGenerator();
|
INarrativeGenerator gen = myContext.getNarrativeGenerator();
|
||||||
|
@ -475,13 +494,13 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
if (childDef == null) {
|
if (childDef == null) {
|
||||||
super.throwExceptionForUnknownChildType(nextChild, type);
|
super.throwExceptionForUnknownChildType(nextChild, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextValue instanceof ExtensionDt) {
|
if (nextValue instanceof ExtensionDt) {
|
||||||
|
|
||||||
extensionUrl = ((ExtensionDt) nextValue).getUrlAsString();
|
extensionUrl = ((ExtensionDt) nextValue).getUrlAsString();
|
||||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource);
|
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource);
|
||||||
|
|
||||||
} else if (extensionUrl != null && childName.equals("extension") == false) {
|
} else if (extensionUrl != null && childName.equals("extension") == false) {
|
||||||
RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild;
|
RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild;
|
||||||
if (extDef.isModifier()) {
|
if (extDef.isModifier()) {
|
||||||
theEventWriter.writeStartElement("modifierExtension");
|
theEventWriter.writeStartElement("modifierExtension");
|
||||||
|
@ -499,14 +518,15 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException,
|
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, XMLStreamWriter theEventWriter,
|
||||||
DataFormatException {
|
BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
||||||
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement, theIncludedResource);
|
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement, theIncludedResource);
|
||||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource);
|
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource);
|
||||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren(), theIncludedResource);
|
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren(), theIncludedResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeExtensionsIfPresent(RuntimeResourceDefinition theResDef, IResource theResource, XMLStreamWriter theWriter, IElement theElement, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
private void encodeExtensionsIfPresent(RuntimeResourceDefinition theResDef, IResource theResource, XMLStreamWriter theWriter, IElement theElement, boolean theIncludedResource)
|
||||||
|
throws XMLStreamException, DataFormatException {
|
||||||
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||||
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
|
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
|
||||||
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredExtensions(), "extension", theIncludedResource);
|
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredExtensions(), "extension", theIncludedResource);
|
||||||
|
@ -516,11 +536,11 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, ResourceReferenceDt theRef) throws XMLStreamException {
|
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, ResourceReferenceDt theRef) throws XMLStreamException {
|
||||||
String reference = theRef.getReference().getValue();
|
String reference = theRef.getReference().getValue();
|
||||||
// if (StringUtils.isBlank(reference)) {
|
// if (StringUtils.isBlank(reference)) {
|
||||||
// if (theRef.getResourceType() != null && StringUtils.isNotBlank(theRef.getResourceId())) {
|
// if (theRef.getResourceType() != null && StringUtils.isNotBlank(theRef.getResourceId())) {
|
||||||
// reference = myContext.getResourceDefinition(theRef.getResourceType()).getName() + '/' + theRef.getResourceId();
|
// reference = myContext.getResourceDefinition(theRef.getResourceType()).getName() + '/' + theRef.getResourceId();
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (!(theRef.getDisplay().isEmpty())) {
|
if (!(theRef.getDisplay().isEmpty())) {
|
||||||
theEventWriter.writeStartElement("display");
|
theEventWriter.writeStartElement("display");
|
||||||
|
@ -536,9 +556,7 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param theIncludedResource
|
* @param theIncludedResource
|
||||||
* Set to true only if this resource is an "included" resource,
|
* Set to true only if this resource is an "included" resource, as opposed to a "root level" resource by itself or in a bundle entry
|
||||||
* as opposed to a "root level" resource by itself or in a bundle
|
|
||||||
* entry
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void encodeResourceToXmlStreamWriter(IResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
private void encodeResourceToXmlStreamWriter(IResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
||||||
|
@ -569,7 +587,8 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
theEventWriter.writeEndElement();
|
theEventWriter.writeEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IResource theResource, XMLStreamWriter theWriter, List<ExtensionDt> extensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IResource theResource, XMLStreamWriter theWriter, List<ExtensionDt> extensions, String tagName,
|
||||||
|
boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
||||||
for (ExtensionDt next : extensions) {
|
for (ExtensionDt next : extensions) {
|
||||||
theWriter.writeStartElement(tagName);
|
theWriter.writeStartElement(tagName);
|
||||||
theWriter.writeAttribute("url", next.getUrl().getValue());
|
theWriter.writeAttribute("url", next.getUrl().getValue());
|
||||||
|
@ -654,7 +673,7 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
} else {
|
} else {
|
||||||
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
||||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||||
// theEventWriter.writeDefaultNamespace(se.getName().getNamespaceURI());
|
// theEventWriter.writeDefaultNamespace(se.getName().getNamespaceURI());
|
||||||
} else {
|
} else {
|
||||||
theEventWriter.writeStartElement(se.getName().getNamespaceURI(), se.getName().getLocalPart());
|
theEventWriter.writeStartElement(se.getName().getNamespaceURI(), se.getName().getLocalPart());
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public abstract class BaseClient {
|
||||||
private boolean myKeepResponses = false;
|
private boolean myKeepResponses = false;
|
||||||
private HttpResponse myLastResponse;
|
private HttpResponse myLastResponse;
|
||||||
private String myLastResponseBody;
|
private String myLastResponseBody;
|
||||||
private boolean myPrettyPrint = false;
|
private Boolean myPrettyPrint = false;
|
||||||
|
|
||||||
private final String myUrlBase;
|
private final String myUrlBase;
|
||||||
|
|
||||||
|
@ -271,9 +271,17 @@ public abstract class BaseClient {
|
||||||
* HAPI based servers (and any other servers which might implement it).
|
* HAPI based servers (and any other servers which might implement it).
|
||||||
*/
|
*/
|
||||||
public boolean isPrettyPrint() {
|
public boolean isPrettyPrint() {
|
||||||
return myPrettyPrint;
|
return Boolean.TRUE.equals(myPrettyPrint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note that this is currently a non-standard flag (_pretty) which is supported only by
|
||||||
|
* HAPI based servers (and any other servers which might implement it).
|
||||||
|
*/
|
||||||
|
public Boolean getPrettyPrint() {
|
||||||
|
return myPrettyPrint;
|
||||||
|
}
|
||||||
|
|
||||||
private void keepResponseAndLogIt(boolean theLogRequestAndResponse, HttpResponse response, String responseString) {
|
private void keepResponseAndLogIt(boolean theLogRequestAndResponse, HttpResponse response, String responseString) {
|
||||||
if (myKeepResponses) {
|
if (myKeepResponses) {
|
||||||
myLastResponse = response;
|
myLastResponse = response;
|
||||||
|
@ -330,7 +338,7 @@ public abstract class BaseClient {
|
||||||
* Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note that this is currently a non-standard flag (_pretty) which is supported only by
|
* Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note that this is currently a non-standard flag (_pretty) which is supported only by
|
||||||
* HAPI based servers (and any other servers which might implement it).
|
* HAPI based servers (and any other servers which might implement it).
|
||||||
*/
|
*/
|
||||||
public BaseClient setPrettyPrint(boolean thePrettyPrint) {
|
public BaseClient setPrettyPrint(Boolean thePrettyPrint) {
|
||||||
myPrettyPrint = thePrettyPrint;
|
myPrettyPrint = thePrettyPrint;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceResponseHandler<Conformance> binding = new ResourceResponseHandler<Conformance>(Conformance.class);
|
ResourceResponseHandler<Conformance> binding = new ResourceResponseHandler<Conformance>(Conformance.class, null);
|
||||||
Conformance resp = invokeClient(binding, invocation, myLogRequestAndResponse);
|
Conformance resp = invokeClient(binding, invocation, myLogRequestAndResponse);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
@ -181,12 +181,16 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends IResource> T read(final Class<T> theType, IdDt theId) {
|
public <T extends IResource> T read(final Class<T> theType, IdDt theId) {
|
||||||
|
if (theId == null || theId.hasIdPart() == false) {
|
||||||
|
throw new IllegalArgumentException("theId does not contain a valid ID, is: " + theId);
|
||||||
|
}
|
||||||
|
|
||||||
HttpGetClientInvocation invocation = ReadMethodBinding.createReadInvocation(theId, toResourceName(theType));
|
HttpGetClientInvocation invocation = ReadMethodBinding.createReadInvocation(theId, toResourceName(theType));
|
||||||
if (isKeepResponses()) {
|
if (isKeepResponses()) {
|
||||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType);
|
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, theId);
|
||||||
T resp = invokeClient(binding, invocation, myLogRequestAndResponse);
|
T resp = invokeClient(binding, invocation, myLogRequestAndResponse);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
@ -291,7 +295,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType);
|
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, theId);
|
||||||
T resp = invokeClient(binding, invocation, myLogRequestAndResponse);
|
T resp = invokeClient(binding, invocation, myLogRequestAndResponse);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
@ -594,9 +598,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
private final class ResourceResponseHandler<T extends IResource> implements IClientResponseHandler<T> {
|
private final class ResourceResponseHandler<T extends IResource> implements IClientResponseHandler<T> {
|
||||||
|
|
||||||
private Class<T> myType;
|
private Class<T> myType;
|
||||||
|
private IdDt myId;
|
||||||
|
|
||||||
public ResourceResponseHandler(Class<T> theType) {
|
public ResourceResponseHandler(Class<T> theType, IdDt theId) {
|
||||||
myType = theType;
|
myType = theType;
|
||||||
|
myId=theId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -606,7 +612,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
||||||
}
|
}
|
||||||
IParser parser = respType.newParser(myContext);
|
IParser parser = respType.newParser(myContext);
|
||||||
return parser.parseResource(myType, theResponseReader);
|
T retVal = parser.parseResource(myType, theResponseReader);
|
||||||
|
|
||||||
|
if (myId != null) {
|
||||||
|
retVal.setId(myId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.rest.gclient;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
|
||||||
public class StringParam implements IParam {
|
public class StringParam implements IParam {
|
||||||
|
@ -54,6 +55,8 @@ public class StringParam implements IParam {
|
||||||
|
|
||||||
ICriterion value(String theValue);
|
ICriterion value(String theValue);
|
||||||
|
|
||||||
|
ICriterion value(StringDt theValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StringExactly implements IStringMatch {
|
private class StringExactly implements IStringMatch {
|
||||||
|
@ -61,6 +64,11 @@ public class StringParam implements IParam {
|
||||||
public ICriterion value(String theValue) {
|
public ICriterion value(String theValue) {
|
||||||
return new StringCriterion(getParamName() + Constants.PARAMQUALIFIER_STRING_EXACT, theValue);
|
return new StringCriterion(getParamName() + Constants.PARAMQUALIFIER_STRING_EXACT, theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICriterion value(StringDt theValue) {
|
||||||
|
return new StringCriterion(getParamName() + Constants.PARAMQUALIFIER_STRING_EXACT, theValue.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StringMatches implements IStringMatch {
|
private class StringMatches implements IStringMatch {
|
||||||
|
@ -68,6 +76,11 @@ public class StringParam implements IParam {
|
||||||
public ICriterion value(String theValue) {
|
public ICriterion value(String theValue) {
|
||||||
return new StringCriterion(getParamName(), theValue);
|
return new StringCriterion(getParamName(), theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICriterion value(StringDt theValue) {
|
||||||
|
return new StringCriterion(getParamName(), theValue.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,10 +177,16 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||||
} else {
|
} else {
|
||||||
ourLog.trace("Method {} doesn't match param '{}' is not present", getMethod().getName(), name);
|
ourLog.trace("Method {} doesn't match param '{}' is not present", getMethod().getName(), name);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
methodParamsTemp.add(name);
|
if (qualifiedParamNames.contains(name)) {
|
||||||
|
methodParamsTemp.add(name);
|
||||||
|
} else if (unqualifiedNames.contains(name)) {
|
||||||
|
methodParamsTemp.addAll(theRequest.getUnqualifiedToQualifiedNames().get(name));
|
||||||
|
} else {
|
||||||
|
methodParamsTemp.add(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (myQueryName != null) {
|
if (myQueryName != null) {
|
||||||
|
|
|
@ -24,6 +24,9 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||||
|
@ -57,6 +60,14 @@ public class SearchParameter extends BaseQueryParameter {
|
||||||
this.myRequired = theRequired;
|
this.myRequired = theRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder retVal = new ToStringBuilder(this);
|
||||||
|
retVal.append("name", myName);
|
||||||
|
retVal.append("required", myRequired);
|
||||||
|
return retVal.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
<td>
|
<td>
|
||||||
<th:block th:if="${not result.resource.name.text.empty}" th:text="${result.resource.name.text.value}"/>
|
<th:block th:if="${not result.resource.name.text.empty}" th:text="${result.resource.name.text.value}"/>
|
||||||
<th:block th:if="${result.resource.name.text.empty} and ${not #lists.isEmpty(result.resource.name.coding)} and ${not result.resource.name.coding[0].empty} and ${not result.resource.name.coding[0].display.empty}" th:text="${result.resource.name.coding[0].display}"/>
|
<th:block th:if="${result.resource.name.text.empty} and ${not #lists.isEmpty(result.resource.name.coding)} and ${not result.resource.name.coding[0].empty} and ${not result.resource.name.coding[0].display.empty}" th:text="${result.resource.name.coding[0].display}"/>
|
||||||
<th:block th:if="${result.resource.name.text.empty} and ${not #lists.isEmpty(result.resource.name.coding)} and ${not result.resource.name.coding[0].empty} and ${result.resource.name.coding[0].display.empty}" th:text="?"/>
|
<th:block th:if="${result.resource.name.text.empty} and ${not #lists.isEmpty(result.resource.name.coding)} and ${not result.resource.name.coding[0].empty} and ${result.resource.name.coding[0].display.empty}" th:text="'?'"/>
|
||||||
<!--/*--> Hb <!--*/-->
|
<!--/*--> Hb <!--*/-->
|
||||||
</td>
|
</td>
|
||||||
<td th:narrative="${result.resource.value}">2.2 g/L</td>
|
<td th:narrative="${result.resource.value}">2.2 g/L</td>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.junit.Test;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.PeriodDt;
|
import ca.uhn.fhir.model.dstu.composite.PeriodDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
|
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
|
||||||
|
@ -154,6 +155,11 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
obs.setValue(new StringDt("HELLO!"));
|
obs.setValue(new StringDt("HELLO!"));
|
||||||
value.addResult().setResource(obs);
|
value.addResult().setResource(obs);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.setName(new CodeableConceptDt("AA", "BB"));
|
||||||
|
value.addResult().setResource(obs);
|
||||||
|
}
|
||||||
NarrativeDt generateNarrative = gen.generateNarrative("http://hl7.org/fhir/profiles/DiagnosticReport", value);
|
NarrativeDt generateNarrative = gen.generateNarrative("http://hl7.org/fhir/profiles/DiagnosticReport", value);
|
||||||
String output = generateNarrative.getDiv().getValueAsString();
|
String output = generateNarrative.getDiv().getValueAsString();
|
||||||
|
|
||||||
|
@ -161,8 +167,8 @@ public class DefaultThymeleafNarrativeGeneratorTest {
|
||||||
assertThat(output, StringContains.containsString("<div class=\"hapiHeaderText\"> Some & Diagnostic Report </div>"));
|
assertThat(output, StringContains.containsString("<div class=\"hapiHeaderText\"> Some & Diagnostic Report </div>"));
|
||||||
|
|
||||||
String title = gen.generateTitle(value);
|
String title = gen.generateTitle(value);
|
||||||
ourLog.info(title);
|
// ourLog.info(title);
|
||||||
assertEquals("Some & Diagnostic Report - final - 2 observations", title);
|
assertEquals("Some & Diagnostic Report - final - 3 observations", title);
|
||||||
|
|
||||||
|
|
||||||
// Now try it with the parser
|
// Now try it with the parser
|
||||||
|
|
|
@ -878,7 +878,12 @@ public class XmlParserTest {
|
||||||
"<link rel=\"self\" href=\"http://hl7.org/implement/standards/fhir/valuesets.xml\"/>" +
|
"<link rel=\"self\" href=\"http://hl7.org/implement/standards/fhir/valuesets.xml\"/>" +
|
||||||
"<updated>2014-02-10T04:11:24.435+00:00</updated>" +
|
"<updated>2014-02-10T04:11:24.435+00:00</updated>" +
|
||||||
"<at:deleted-entry xmlns:at=\"http://purl.org/atompub/tombstones/1.0\" ref=\"http://foo/Patient/1\" when=\"2013-02-10T04:11:24.435+00:00\">" +
|
"<at:deleted-entry xmlns:at=\"http://purl.org/atompub/tombstones/1.0\" ref=\"http://foo/Patient/1\" when=\"2013-02-10T04:11:24.435+00:00\">" +
|
||||||
"<link rel=\"self\" href=\"http://foo/Patient/1/_history/2\"/>" +
|
"<at:by>" +
|
||||||
|
"<at:name>John Doe</at:name>" +
|
||||||
|
"<at:email>jdoe@example.org</at:email>" +
|
||||||
|
"</at:by>" +
|
||||||
|
"<at:comment>Removed comment spam</at:comment>" +
|
||||||
|
"<link rel=\"self\" href=\"http://foo/Patient/1/_history/2\"/>" +
|
||||||
"</at:deleted-entry>" +
|
"</at:deleted-entry>" +
|
||||||
"</feed>";
|
"</feed>";
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
@ -893,6 +898,9 @@ public class XmlParserTest {
|
||||||
assertEquals("1", entry.getResource().getId().getIdPart());
|
assertEquals("1", entry.getResource().getId().getIdPart());
|
||||||
assertEquals("2", entry.getResource().getId().getVersionIdPart());
|
assertEquals("2", entry.getResource().getId().getVersionIdPart());
|
||||||
assertEquals("2", ((IdDt)entry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION_ID)).getVersionIdPart());
|
assertEquals("2", ((IdDt)entry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION_ID)).getVersionIdPart());
|
||||||
|
assertEquals("John Doe", entry.getDeletedByName().getValue());
|
||||||
|
assertEquals("jdoe@example.org", entry.getDeletedByEmail().getValue());
|
||||||
|
assertEquals("Removed comment spam", entry.getDeletedComment().getValue());
|
||||||
assertEquals(new InstantDt("2013-02-10T04:11:24.435+00:00"), entry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.DELETED_AT));
|
assertEquals(new InstantDt("2013-02-10T04:11:24.435+00:00"), entry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.DELETED_AT));
|
||||||
|
|
||||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle));
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle));
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.model.dstu.resource.Encounter;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Organization;
|
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
@ -115,6 +116,23 @@ public class GenericClientTest {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getResourceResult() {
|
||||||
|
//@formatter:off
|
||||||
|
String msg =
|
||||||
|
"<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||||
|
+ "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>"
|
||||||
|
+ "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>"
|
||||||
|
+ "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>"
|
||||||
|
+ "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>"
|
||||||
|
+ "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>"
|
||||||
|
+ "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>"
|
||||||
|
+ "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />"
|
||||||
|
+ "</Patient>";
|
||||||
|
//@formatter:on
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
public void testSearchByString() throws Exception {
|
public void testSearchByString() throws Exception {
|
||||||
|
@ -406,6 +424,32 @@ public class GenericClientTest {
|
||||||
assertEquals("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json", capt.getValue().getURI().toString());
|
assertEquals("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json", capt.getValue().getURI().toString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRead() throws Exception {
|
||||||
|
|
||||||
|
String msg = getResourceResult();
|
||||||
|
|
||||||
|
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||||
|
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||||
|
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||||
|
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||||
|
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||||
|
|
||||||
|
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Patient response = client.read(Patient.class, new IdDt("Patient/1234"));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal"));
|
||||||
|
assertEquals("Patient/1234", response.getId().getValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -22,6 +22,7 @@ import org.junit.Test;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
@ -127,6 +128,19 @@ public class StringParameterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchExactMatchOptional() throws Exception {
|
||||||
|
{
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?ccc:exact=aaa");
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals(1, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClass() throws Exception {
|
public static void afterClass() throws Exception {
|
||||||
ourServer.stop();
|
ourServer.stop();
|
||||||
|
@ -190,6 +204,25 @@ public class StringParameterTest {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Search
|
||||||
|
public List<Patient> findPatientWithOptional(@OptionalParam(name = "ccc") StringParam theParam) {
|
||||||
|
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||||
|
|
||||||
|
if (theParam.isExact() && theParam.getValue().equals("aaa")) {
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("1");
|
||||||
|
retVal.add(patient);
|
||||||
|
}
|
||||||
|
if (!theParam.isExact() && theParam.getValue().toLowerCase().equals("aaa")) {
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("2");
|
||||||
|
retVal.add(patient);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends IResource> getResourceType() {
|
public Class<? extends IResource> getResourceType() {
|
||||||
return Patient.class;
|
return Patient.class;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<value>furore , Spark - Furore Reference Server , http://spark.furore.com/fhir</value>
|
<value>furore , Spark - Furore Reference Server , http://spark.furore.com/fhir</value>
|
||||||
<value>blaze , Blaze (Orion Health) , https://fhir.orionhealth.com/blaze/fhir</value>
|
<value>blaze , Blaze (Orion Health) , https://fhir.orionhealth.com/blaze/fhir</value>
|
||||||
<value>oridashi , Oridashi , http://demo.oridashi.com.au:8190</value>
|
<value>oridashi , Oridashi , http://demo.oridashi.com.au:8190</value>
|
||||||
<value>fhirbase , FHIRPlace (Health Samurai) , http://try-fhirplace.hospital-systems.com/ </value>
|
<!-- <value>fhirbase , FHIRPlace (Health Samurai) , http://try-fhirplace.hospital-systems.com/ </value> -->
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
|
@ -82,9 +82,15 @@ public class Controller {
|
||||||
theModel.put("notHome", true);
|
theModel.put("notHome", true);
|
||||||
theModel.put("extraBreadcrumb", "About");
|
theModel.put("extraBreadcrumb", "About");
|
||||||
|
|
||||||
|
ourLog.info(logPrefix(theModel) + "Displayed about page");
|
||||||
|
|
||||||
return "about";
|
return "about";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String logPrefix(ModelMap theModel) {
|
||||||
|
return "[server=" + theModel.get("serverId") + "] - ";
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(value = { "/conformance" })
|
@RequestMapping(value = { "/conformance" })
|
||||||
public String actionConformance(final HomeRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
public String actionConformance(final HomeRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||||
addCommonParams(theRequest, theModel);
|
addCommonParams(theRequest, theModel);
|
||||||
|
@ -102,6 +108,8 @@ public class Controller {
|
||||||
|
|
||||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, "Loaded conformance");
|
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, "Loaded conformance");
|
||||||
|
|
||||||
|
ourLog.info(logPrefix(theModel) + "Displayed conformance profile");
|
||||||
|
|
||||||
return "result";
|
return "result";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +151,8 @@ public class Controller {
|
||||||
long delay = System.currentTimeMillis() - start;
|
long delay = System.currentTimeMillis() - start;
|
||||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||||
|
|
||||||
|
ourLog.info(logPrefix(theModel) + "Deleted resource of type " + def.getName());
|
||||||
|
|
||||||
return "result";
|
return "result";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,14 +195,18 @@ public class Controller {
|
||||||
String vid = theReq.getParameter("resource-tags-vid");
|
String vid = theReq.getParameter("resource-tags-vid");
|
||||||
if (isNotBlank(vid)) {
|
if (isNotBlank(vid)) {
|
||||||
client.getTags().forResource(resType, id, vid).execute();
|
client.getTags().forResource(resType, id, vid).execute();
|
||||||
|
ourLog.info(logPrefix(theModel) + "Got tags for type " + def.getName() + " ID " + id + " version" + vid);
|
||||||
} else {
|
} else {
|
||||||
client.getTags().forResource(resType, id).execute();
|
client.getTags().forResource(resType, id).execute();
|
||||||
|
ourLog.info(logPrefix(theModel) + "Got tags for type " + def.getName() + " ID " + id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.getTags().forResource(resType).execute();
|
client.getTags().forResource(resType).execute();
|
||||||
|
ourLog.info(logPrefix(theModel) + "Got tags for type " + def.getName());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.getTags().execute();
|
client.getTags().execute();
|
||||||
|
ourLog.info(logPrefix(theModel) + "Got tags for server");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
returnsResource = handleClientException(client, e, theModel);
|
returnsResource = handleClientException(client, e, theModel);
|
||||||
|
@ -230,6 +244,7 @@ public class Controller {
|
||||||
|
|
||||||
String url = defaultString(theReq.getParameter("page-url"));
|
String url = defaultString(theReq.getParameter("page-url"));
|
||||||
if (!url.startsWith(theModel.get("base").toString())) {
|
if (!url.startsWith(theModel.get("base").toString())) {
|
||||||
|
ourLog.warn(logPrefix(theModel) + "Refusing to load page URL: {}", url);
|
||||||
theModel.put("errorMsg", "Invalid page URL: " + url);
|
theModel.put("errorMsg", "Invalid page URL: " + url);
|
||||||
return "result";
|
return "result";
|
||||||
}
|
}
|
||||||
|
@ -240,6 +255,7 @@ public class Controller {
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
|
ourLog.info(logPrefix(theModel) + "Loading paging URL: {}", url);
|
||||||
client.loadPage().url(url).execute();
|
client.loadPage().url(url).execute();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
returnsResource = handleClientException(client, e, theModel);
|
returnsResource = handleClientException(client, e, theModel);
|
||||||
|
@ -284,7 +300,9 @@ public class Controller {
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
client.read(def.getImplementingClass(), new IdDt(def.getName(), id, versionId));
|
IdDt resid = new IdDt(def.getName(), id, versionId);
|
||||||
|
ourLog.info(logPrefix(theModel) + "Reading resource: {}", resid);
|
||||||
|
client.read(def.getImplementingClass(), resid);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
returnsResource = handleClientException(client, e, theModel);
|
returnsResource = handleClientException(client, e, theModel);
|
||||||
}
|
}
|
||||||
|
@ -360,6 +378,8 @@ public class Controller {
|
||||||
theModel.put("updateResourceId", updateId);
|
theModel.put("updateResourceId", updateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.info(logPrefix(theModel) + "Showing resource page: {}", resourceName);
|
||||||
|
|
||||||
return "resource";
|
return "resource";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,8 +391,8 @@ public class Controller {
|
||||||
JsonGenerator clientCodeJsonWriter = Json.createGenerator(clientCodeJsonStringWriter);
|
JsonGenerator clientCodeJsonWriter = Json.createGenerator(clientCodeJsonStringWriter);
|
||||||
clientCodeJsonWriter.writeStartObject();
|
clientCodeJsonWriter.writeStartObject();
|
||||||
clientCodeJsonWriter.write("action", "search");
|
clientCodeJsonWriter.write("action", "search");
|
||||||
clientCodeJsonWriter.write("base", (String)theModel.get("base"));
|
clientCodeJsonWriter.write("base", (String) theModel.get("base"));
|
||||||
|
|
||||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||||
|
|
||||||
IUntypedQuery search = client.search();
|
IUntypedQuery search = client.search();
|
||||||
|
@ -389,29 +409,45 @@ public class Controller {
|
||||||
query = search.forAllResources();
|
query = search.forAllResources();
|
||||||
clientCodeJsonWriter.writeNull("resource");
|
clientCodeJsonWriter.writeNull("resource");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client.getPrettyPrint() != null) {
|
||||||
|
clientCodeJsonWriter.write("pretty", client.getPrettyPrint().toString());
|
||||||
|
} else {
|
||||||
|
clientCodeJsonWriter.writeNull("pretty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client.getEncoding() != null) {
|
||||||
|
clientCodeJsonWriter.write("format", client.getEncoding().getRequestContentType());
|
||||||
|
} else {
|
||||||
|
clientCodeJsonWriter.writeNull("format");
|
||||||
|
}
|
||||||
|
|
||||||
String outcomeDescription = "Search for Resources";
|
String outcomeDescription = "Search for Resources";
|
||||||
|
|
||||||
|
clientCodeJsonWriter.writeStartArray("params");
|
||||||
int paramIdx = -1;
|
int paramIdx = -1;
|
||||||
while (true) {
|
while (true) {
|
||||||
paramIdx++;
|
paramIdx++;
|
||||||
|
|
||||||
String paramIdxString = Integer.toString(paramIdx);
|
String paramIdxString = Integer.toString(paramIdx);
|
||||||
boolean shouldContinue = handleSearchParam(paramIdxString, theReq, query);
|
boolean shouldContinue = handleSearchParam(paramIdxString, theReq, query, clientCodeJsonWriter);
|
||||||
if (!shouldContinue) {
|
if (!shouldContinue) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clientCodeJsonWriter.writeEnd();
|
||||||
|
|
||||||
|
clientCodeJsonWriter.writeStartArray("includes");
|
||||||
String[] incValues = theReq.getParameterValues(Constants.PARAM_INCLUDE);
|
String[] incValues = theReq.getParameterValues(Constants.PARAM_INCLUDE);
|
||||||
if (incValues != null) {
|
if (incValues != null) {
|
||||||
for (String next : incValues) {
|
for (String next : incValues) {
|
||||||
if (isNotBlank(next)) {
|
if (isNotBlank(next)) {
|
||||||
query.include(new Include(next));
|
query.include(new Include(next));
|
||||||
|
clientCodeJsonWriter.write(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clientCodeJsonWriter.writeEnd();
|
||||||
|
|
||||||
String limit = theReq.getParameter("resource-search-limit");
|
String limit = theReq.getParameter("resource-search-limit");
|
||||||
if (isNotBlank(limit)) {
|
if (isNotBlank(limit)) {
|
||||||
|
@ -419,12 +455,18 @@ public class Controller {
|
||||||
theModel.put("errorMsg", "Search limit must be a numeric value.");
|
theModel.put("errorMsg", "Search limit must be a numeric value.");
|
||||||
return "resource";
|
return "resource";
|
||||||
}
|
}
|
||||||
query.limitTo(Integer.parseInt(limit));
|
int limitInt = Integer.parseInt(limit);
|
||||||
|
query.limitTo(limitInt);
|
||||||
|
clientCodeJsonWriter.write("limit", limit);
|
||||||
|
} else {
|
||||||
|
clientCodeJsonWriter.writeNull("limit");
|
||||||
}
|
}
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
ResultType returnsResource;
|
ResultType returnsResource;
|
||||||
try {
|
try {
|
||||||
|
ourLog.info(logPrefix(theModel) + "Executing a search");
|
||||||
|
|
||||||
query.execute();
|
query.execute();
|
||||||
returnsResource = ResultType.BUNDLE;
|
returnsResource = ResultType.BUNDLE;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -438,7 +480,7 @@ public class Controller {
|
||||||
clientCodeJsonWriter.close();
|
clientCodeJsonWriter.close();
|
||||||
String clientCodeJson = clientCodeJsonStringWriter.toString();
|
String clientCodeJson = clientCodeJsonStringWriter.toString();
|
||||||
theModel.put("clientCodeJson", clientCodeJson);
|
theModel.put("clientCodeJson", clientCodeJson);
|
||||||
|
|
||||||
return "result";
|
return "result";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,11 +508,17 @@ public class Controller {
|
||||||
return "home";
|
return "home";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultType returnsResource = ResultType.BUNDLE;
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
client.transaction().withBundle(bundle).execute();
|
try {
|
||||||
|
ourLog.info(logPrefix(theModel) + "Executing transaction with {} resources", bundle.size());
|
||||||
|
client.transaction().withBundle(bundle).execute();
|
||||||
|
} catch (Exception e) {
|
||||||
|
returnsResource = handleClientException(client, e, theModel);
|
||||||
|
}
|
||||||
long delay = System.currentTimeMillis() - start;
|
long delay = System.currentTimeMillis() - start;
|
||||||
|
|
||||||
processAndAddLastClientInvocation(client, ResultType.BUNDLE, theModel, delay, "Transaction");
|
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, "Transaction");
|
||||||
|
|
||||||
return "result";
|
return "result";
|
||||||
}
|
}
|
||||||
|
@ -555,6 +603,7 @@ public class Controller {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
ResultType returnsResource = ResultType.RESOURCE;
|
ResultType returnsResource = ResultType.RESOURCE;
|
||||||
outcomeDescription = "";
|
outcomeDescription = "";
|
||||||
|
boolean update = false;
|
||||||
try {
|
try {
|
||||||
if (validate) {
|
if (validate) {
|
||||||
outcomeDescription = "Validate Resource";
|
outcomeDescription = "Validate Resource";
|
||||||
|
@ -564,6 +613,7 @@ public class Controller {
|
||||||
if (isNotBlank(id)) {
|
if (isNotBlank(id)) {
|
||||||
outcomeDescription = "Update Resource";
|
outcomeDescription = "Update Resource";
|
||||||
client.update(id, resource);
|
client.update(id, resource);
|
||||||
|
update = true;
|
||||||
} else {
|
} else {
|
||||||
outcomeDescription = "Create Resource";
|
outcomeDescription = "Create Resource";
|
||||||
client.create(resource);
|
client.create(resource);
|
||||||
|
@ -576,6 +626,18 @@ public class Controller {
|
||||||
|
|
||||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (validate) {
|
||||||
|
ourLog.info(logPrefix(theModel) + "Validated resource of type " + getResourceType(theReq).getName());
|
||||||
|
} else if (update) {
|
||||||
|
ourLog.info(logPrefix(theModel) + "Updated resource of type " + getResourceType(theReq).getName());
|
||||||
|
} else {
|
||||||
|
ourLog.info(logPrefix(theModel) + "Created resource of type " + getResourceType(theReq).getName());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
ourLog.warn("Failed to determine resource type from request", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doActionHistory(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel, String theMethod, String theMethodDescription) {
|
private void doActionHistory(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel, String theMethod, String theMethodDescription) {
|
||||||
|
@ -603,11 +665,18 @@ public class Controller {
|
||||||
limit = Integer.parseInt(limitStr);
|
limit = Integer.parseInt(limitStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultType returnsResource = ResultType.BUNDLE;
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
client.history(type, id, since, limit);
|
try {
|
||||||
|
ourLog.info(logPrefix(theModel) + "Retrieving history for type {} ID {} since {}", new Object[] { type, id, since });
|
||||||
|
client.history(type, id, since, limit);
|
||||||
|
} catch (Exception e) {
|
||||||
|
returnsResource = handleClientException(client, e, theModel);
|
||||||
|
}
|
||||||
long delay = System.currentTimeMillis() - start;
|
long delay = System.currentTimeMillis() - start;
|
||||||
|
|
||||||
processAndAddLastClientInvocation(client, ResultType.BUNDLE, theModel, delay, theMethodDescription);
|
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, theMethodDescription);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,42 +839,59 @@ public class Controller {
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleSearchParam(String paramIdxString, HttpServletRequest theReq, IQuery theQuery) {
|
private boolean handleSearchParam(String paramIdxString, HttpServletRequest theReq, IQuery theQuery, JsonGenerator theClientCodeJsonWriter) {
|
||||||
String nextName = theReq.getParameter("param." + paramIdxString + ".name");
|
String nextName = theReq.getParameter("param." + paramIdxString + ".name");
|
||||||
if (isBlank(nextName)) {
|
if (isBlank(nextName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String nextQualifier = StringUtils.defaultString(theReq.getParameter("param." + paramIdxString + ".qualifier"));
|
String nextQualifier = StringUtils.defaultString(theReq.getParameter("param." + paramIdxString + ".qualifier"));
|
||||||
|
|
||||||
String nextType = theReq.getParameter("param." + paramIdxString + ".type");
|
String nextType = theReq.getParameter("param." + paramIdxString + ".type");
|
||||||
|
|
||||||
StringBuilder b = new StringBuilder();
|
List<String> parts = new ArrayList<String>();
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
b.append(defaultString(theReq.getParameter("param." + paramIdxString + "." + i)));
|
parts.add(defaultString(theReq.getParameter("param." + paramIdxString + "." + i)));
|
||||||
}
|
|
||||||
|
|
||||||
String paramValue = b.toString();
|
|
||||||
if (isBlank(paramValue)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> values;
|
||||||
if ("token".equals(nextType)) {
|
if ("token".equals(nextType)) {
|
||||||
if (paramValue.length() < 2) {
|
if (isBlank(parts.get(2))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
values = Collections.singletonList(StringUtils.join(parts, ""));
|
||||||
|
} else if ("date".equals(nextType)) {
|
||||||
|
values = new ArrayList<String>();
|
||||||
|
if (isNotBlank(parts.get(1))) {
|
||||||
|
values.add(StringUtils.join(parts.get(0), parts.get(1)));
|
||||||
|
}
|
||||||
|
if (isNotBlank(parts.get(3))) {
|
||||||
|
values.add(StringUtils.join(parts.get(2), parts.get(3)));
|
||||||
|
}
|
||||||
|
if (values.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
values = Collections.singletonList(StringUtils.join(parts, ""));
|
||||||
|
if (isBlank(values.get(0))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if ("xml".equals(theReq.getParameter("encoding"))) {
|
for (String nextValue : values) {
|
||||||
// query.encodedXml();
|
|
||||||
// }else if ("json".equals(theReq.getParameter("encoding"))) {
|
|
||||||
// query.encodedJson();
|
|
||||||
// }
|
|
||||||
|
|
||||||
theQuery.where(new StringParam(nextName + nextQualifier).matches().value(paramValue));
|
theClientCodeJsonWriter.writeStartObject();
|
||||||
|
theClientCodeJsonWriter.write("type", nextType);
|
||||||
|
theClientCodeJsonWriter.write("name", nextName);
|
||||||
|
theClientCodeJsonWriter.write("qualifier", nextQualifier);
|
||||||
|
theClientCodeJsonWriter.write("value", nextValue);
|
||||||
|
theClientCodeJsonWriter.writeEnd();
|
||||||
|
|
||||||
|
theQuery.where(new StringParam(nextName + nextQualifier).matches().value(nextValue));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(theReq.getParameter("param." + paramIdxString + ".0.name"))) {
|
if (StringUtils.isNotBlank(theReq.getParameter("param." + paramIdxString + ".0.name"))) {
|
||||||
handleSearchParam(paramIdxString + ".0", theReq, theQuery);
|
handleSearchParam(paramIdxString + ".0", theReq, theQuery, theClientCodeJsonWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -15,8 +15,9 @@
|
||||||
<value>home , Localhost Server , http://localhost:8887/fhir/context </value>
|
<value>home , Localhost Server , http://localhost:8887/fhir/context </value>
|
||||||
<value>hi , Health Intersections , http://fhir.healthintersections.com.au/open</value>
|
<value>hi , Health Intersections , http://fhir.healthintersections.com.au/open</value>
|
||||||
<value>furore , Spark - Furore Reference Server , http://spark.furore.com/fhir</value>
|
<value>furore , Spark - Furore Reference Server , http://spark.furore.com/fhir</value>
|
||||||
<value>blaze , Blaze (Orion Health) , https://his-medicomp-gateway.orionhealth.com/blaze/fhir</value>
|
<value>blaze , Blaze (Orion Health) , https://fhir.orionhealth.com/blaze/fhir</value>
|
||||||
<value>oridashi , Oridashi , http://demo.oridashi.com.au:8190</value>
|
<value>oridashi , Oridashi , http://demo.oridashi.com.au:8190</value>
|
||||||
|
<value>fhirbase , FHIRPlace (Health Samurai) , http://try-fhirplace.hospital-systems.com/ </value>
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
|
@ -537,5 +537,11 @@
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
<div th:replace="tmpl-footer :: footer" ></div>
|
<div th:replace="tmpl-footer :: footer" ></div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function () { $("[data-toggle='tooltip']").tooltip(); });
|
||||||
|
</script>
|
||||||
|
-->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
<th:block th:text="${latencyMs} + 'ms'"/>
|
<th:block th:text="${latencyMs} + 'ms'"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
|
||||||
<div th:if="${clientCodeJson} != null" class="panel panel-default">
|
<div th:if="${clientCodeJson} != null" class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
Client Code -
|
Client Code -
|
||||||
|
@ -44,7 +43,6 @@
|
||||||
generateHapi(jsonClientCode, $('#clientCodeBody'));
|
generateHapi(jsonClientCode, $('#clientCodeBody'));
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
-->
|
|
||||||
|
|
||||||
<div th:if="${requestUrl} != null">
|
<div th:if="${requestUrl} != null">
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="searchParamDescription">
|
<div class="searchParamDescription">
|
||||||
<div>
|
<div>
|
||||||
|
<b th:if="${param.name} != null and ${!param.name.empty}" th:text="${param.name} + ' - '" />
|
||||||
<th:block th:text="${param.documentation}" />
|
<th:block th:text="${param.documentation}" />
|
||||||
<th:block th:if="${!param.getUndeclaredExtensionsByUrl(requiredParamExtension).empty}">
|
<th:block th:if="${!param.getUndeclaredExtensionsByUrl(requiredParamExtension).empty}">
|
||||||
<span style="color:#F88;" th:if="${param.getUndeclaredExtensionsByUrl(requiredParamExtension).get(0).value.value}">
|
<span style="color:#F88;" th:if="${param.getUndeclaredExtensionsByUrl(requiredParamExtension).get(0).value.value}">
|
||||||
|
|
|
@ -22,11 +22,20 @@ body {
|
||||||
line-height: 0.85em;
|
line-height: 0.85em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clientCodeComment {
|
||||||
|
color: #4A4;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.clientCodePreamble {
|
.clientCodePreamble {
|
||||||
color: #888;
|
color: #888;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clientCodeIndent {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-size: 1.0em;
|
font-size: 1.0em;
|
||||||
color: #808080;
|
color: #808080;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
function generateHapi(json, container) {
|
function generateHapi(json, container) {
|
||||||
if (json.action == 'search') {
|
if (json.action == 'search') {
|
||||||
generateHapiSearch(json, container);
|
generateHapiSearch(json, container);
|
||||||
|
@ -6,12 +6,17 @@ function generateHapi(json, container) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateHapiSearch(json, container) {
|
function generateHapiSearch(json, container) {
|
||||||
|
container.append($('<span />', {'class': 'clientCodeComment'}).text("// Create a client (only needed once)"));
|
||||||
|
container.append($('<br/>'));
|
||||||
container.append($('<span />', {'class': 'clientCodePreamble'}).text("FhirContext ctx = new FhirContext();"));
|
container.append($('<span />', {'class': 'clientCodePreamble'}).text("FhirContext ctx = new FhirContext();"));
|
||||||
container.append($('<br/>'));
|
container.append($('<br/>'));
|
||||||
container.append($('<span />', {'class': 'clientCodePreamble'}).text("IGenericClient client = ctx.newRestfulGenericClient(\"" + json.base + "\");"));
|
container.append($('<span />', {'class': 'clientCodePreamble'}).text("IGenericClient client = ctx.newRestfulGenericClient(\"" + json.base + "\");"));
|
||||||
container.append($('<br/>'));
|
container.append($('<br/>'));
|
||||||
|
container.append($('<br/>'));
|
||||||
|
container.append($('<span />', {'class': 'clientCodeComment'}).text("// Invoke the client"));
|
||||||
|
container.append($('<br/>'));
|
||||||
|
|
||||||
var searchLine = 'client.search()';
|
var searchLine = 'Bundle bundle = client.search()';
|
||||||
if (json.resource != null) {
|
if (json.resource != null) {
|
||||||
searchLine = searchLine + '.forResource(' + json.resource + '.class)';
|
searchLine = searchLine + '.forResource(' + json.resource + '.class)';
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,4 +24,60 @@ function generateHapiSearch(json, container) {
|
||||||
}
|
}
|
||||||
container.append($('<span />', {'class': 'clientCodeMain'}).text(searchLine));
|
container.append($('<span />', {'class': 'clientCodeMain'}).text(searchLine));
|
||||||
|
|
||||||
|
var indented = $('<div />', {'class': 'clientCodeIndent'});
|
||||||
|
container.append(indented);
|
||||||
|
|
||||||
|
if (json.pretty) {
|
||||||
|
indented.append($('<span />', {'class': 'clientCodeMain'}).text('.setPrettyPrint(' + json.pretty + ')'));
|
||||||
|
indented.append($('<br/>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.format) {
|
||||||
|
indented.append($('<span />', {'class': 'clientCodeMain'}).text('.setEncoding(EncodingEnum.' + json.format.toUpperCase() + ')'));
|
||||||
|
indented.append($('<br/>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < json.params.length; i++) {
|
||||||
|
var nextParam = json.params[i];
|
||||||
|
var paramLine = null;
|
||||||
|
if (nextParam.type == 'string') {
|
||||||
|
paramLine = '.where(new StringParam("' + nextParam.name + '").matches().value("' + nextParam.value + '"))';
|
||||||
|
} else if (nextParam.type == 'token') {
|
||||||
|
var idx = nextParam.value.indexOf('|');
|
||||||
|
if (idx == -1) {
|
||||||
|
paramLine = '.where(new TokenParam("' + nextParam.name + '").exactly().code("' + nextParam.value + '"))';
|
||||||
|
} else {
|
||||||
|
paramLine = '.where(new TokenParam("' + nextParam.name + '").exactly().systemAndCode("' + nextParam.value.substring(0,idx) + '", "' + nextParam.value.substring(idx+1) + '"))';
|
||||||
|
}
|
||||||
|
} else if (nextParam.type == 'number') {
|
||||||
|
paramLine = '.where(new NumberParam("' + nextParam.name + '").exactly().value("' + nextParam.value + '"))';
|
||||||
|
} else if (nextParam.type == 'date') {
|
||||||
|
if (nextParam.value.substring(0,2) == '>=') {
|
||||||
|
paramLine = '.where(new DateParam("' + nextParam.name + '").afterOrEquals().value("' + nextParam.value.substring(2) + '"))';
|
||||||
|
} else if (nextParam.value.substring(0,1) == '>') {
|
||||||
|
paramLine = '.where(new DateParam("' + nextParam.name + '").after().value("' + nextParam.value.substring(1) + '"))';
|
||||||
|
} else if (nextParam.value.substring(0,2) == '<=') {
|
||||||
|
paramLine = '.where(new DateParam("' + nextParam.name + '").beforeOrEquals().value("' + nextParam.value.substring(2) + '"))';
|
||||||
|
} else if (nextParam.value.substring(0,1) == '<') {
|
||||||
|
paramLine = '.where(new DateParam("' + nextParam.name + '").before().value("' + nextParam.value.substring(1) + '"))';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (paramLine != null) {
|
||||||
|
indented.append($('<span />', {'class': 'clientCodeMain'}).text(paramLine));
|
||||||
|
indented.append($('<br/>'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < json.includes.length; i++) {
|
||||||
|
indented.append($('<span />', {'class': 'clientCodeMain'}).text('.include(new Include("' + json.includes[i] + '"))'));
|
||||||
|
indented.append($('<br/>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.limit) {
|
||||||
|
indented.append($('<span />', {'class': 'clientCodeMain'}).text('.limitTo(' + json.limit + ')'));
|
||||||
|
indented.append($('<br/>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
indented.append($('<span />', {'class': 'clientCodeMain'}).text('.execute();'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,55 +95,70 @@ function addSearchControls(theSearchParamType, theSearchParamName, theSearchPara
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else if (theSearchParamType == 'date') {
|
} else if (theSearchParamType == 'date') {
|
||||||
var qualifier = $('<input />', {type:'hidden', id:'param.'+theRowNum+'.0', id:'param.'+theRowNum+'.0'});
|
addSearchControlDate(theSearchParamName, theContainerRowNum, theRowNum, true);
|
||||||
|
addSearchControlDate(theSearchParamName, theContainerRowNum, theRowNum, false);
|
||||||
if (/date$/.test(theSearchParamName)) {
|
|
||||||
var input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DD' });
|
|
||||||
} else {
|
|
||||||
var input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DDTHH:mm:ss' });
|
|
||||||
}
|
|
||||||
var qualifierDiv = $('<div />');
|
|
||||||
input.append(
|
|
||||||
qualifierDiv,
|
|
||||||
$('<input />', { type:'text', 'class':'form-control', id: 'param.' + theRowNum + '.1' }),
|
|
||||||
$('<div />', { 'class':'input-group-addon', 'style':'padding:6px;'} ).append(
|
|
||||||
$('<i />', { 'class':'fa fa-chevron-circle-down'})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
input.datetimepicker({
|
|
||||||
pickTime: false,
|
|
||||||
showToday: true
|
|
||||||
});
|
|
||||||
// Set up the qualifier dropdown after we've initialized the datepicker, since it
|
|
||||||
// overrides all addon buttons while it inits..
|
|
||||||
qualifierDiv.addClass('input-group-btn');
|
|
||||||
var qualifierBtn = $('<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">=</button>');
|
|
||||||
var qualifierBtnEq = $('<a>=</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '='); });
|
|
||||||
var qualifierBtnGt = $('<a>></a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '>'); });
|
|
||||||
var qualifierBtnGe = $('<a>>=</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '>='); });
|
|
||||||
var qualifierBtnLt = $('<a><</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '<'); });
|
|
||||||
var qualifierBtnLe = $('<a><=</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '<='); });
|
|
||||||
qualifierDiv.append(
|
|
||||||
qualifierBtn,
|
|
||||||
$('<ul class="dropdown-menu" role="menu">').append(
|
|
||||||
$('<li />').append(qualifierBtnEq),
|
|
||||||
$('<li />').append(qualifierBtnGt),
|
|
||||||
$('<li />').append(qualifierBtnGe),
|
|
||||||
$('<li />').append(qualifierBtnLt),
|
|
||||||
$('<li />').append(qualifierBtnLe)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$('#search-param-rowopts-' + theContainerRowNum).append(
|
|
||||||
qualifier,
|
|
||||||
$('<div />', { 'class': 'col-sm-4' }).append(
|
|
||||||
input
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addSearchControlDate(theSearchParamName, theContainerRowNum, theRowNum, theLower) {
|
||||||
|
var inputId0 = theRowNum + '.' + (theLower ? 0 : 2);
|
||||||
|
var inputId1 = theRowNum + '.' + (theLower ? 1 : 3);
|
||||||
|
|
||||||
|
var qualifier = $('<input />', {type:'hidden', id:'param.'+inputId0, id:'param.'+inputId0});
|
||||||
|
|
||||||
|
if (/date$/.test(theSearchParamName)) {
|
||||||
|
var input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DD' });
|
||||||
|
} else {
|
||||||
|
var input = $('<div />', { 'class':'input-group date', 'data-date-format':'YYYY-MM-DDTHH:mm:ss' });
|
||||||
|
}
|
||||||
|
var qualifierDiv = $('<div />');
|
||||||
|
|
||||||
|
input.append(
|
||||||
|
qualifierDiv,
|
||||||
|
$('<input />', { type:'text', 'class':'form-control', id: 'param.' + inputId1 }),
|
||||||
|
$('<div />', { 'class':'input-group-addon', 'style':'padding:6px;'} ).append(
|
||||||
|
$('<i />', { 'class':'fa fa-chevron-circle-down'})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
input.datetimepicker({
|
||||||
|
pickTime: false,
|
||||||
|
showToday: true
|
||||||
|
});
|
||||||
|
// Set up the qualifier dropdown after we've initialized the datepicker, since it
|
||||||
|
// overrides all addon buttons while it inits..
|
||||||
|
qualifierDiv.addClass('input-group-btn');
|
||||||
|
var qualifierTooltip = "Set a qualifier and a date to specify a boundary date. Set two qualifiers and dates to specify a range.";
|
||||||
|
var qualifierBtn = $('<button />', {type:'button', 'class':'btn btn-default dropdown-toggle', 'data-toggle':'dropdown', 'data-placement':'top', 'title':qualifierTooltip}).text('=');
|
||||||
|
qualifierBtn.tooltip({
|
||||||
|
'selector': '',
|
||||||
|
'placement': 'top',
|
||||||
|
'container':'body'
|
||||||
|
});
|
||||||
|
var qualifierBtnEq = $('<a>=</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '='); });
|
||||||
|
var qualifierBtnGt = $('<a>></a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '>'); });
|
||||||
|
var qualifierBtnGe = $('<a>>=</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '>='); });
|
||||||
|
var qualifierBtnLt = $('<a><</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '<'); });
|
||||||
|
var qualifierBtnLe = $('<a><=</a>').click(function() { updateSearchDateQualifier(qualifierBtn, qualifier, '<='); });
|
||||||
|
qualifierDiv.append(
|
||||||
|
qualifierBtn,
|
||||||
|
$('<ul class="dropdown-menu" role="menu">').append(
|
||||||
|
$('<li />').append(qualifierBtnEq),
|
||||||
|
$('<li />').append(qualifierBtnGt),
|
||||||
|
$('<li />').append(qualifierBtnGe),
|
||||||
|
$('<li />').append(qualifierBtnLt),
|
||||||
|
$('<li />').append(qualifierBtnLe)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$('#search-param-rowopts-' + theContainerRowNum).append(
|
||||||
|
qualifier,
|
||||||
|
$('<div />', { 'class': 'col-sm-3' }).append(
|
||||||
|
input
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function handleSearchParamTypeChange(select, params, rowNum) {
|
function handleSearchParamTypeChange(select, params, rowNum) {
|
||||||
var oldVal = select.prevVal;
|
var oldVal = select.prevVal;
|
||||||
var newVal = select.val();
|
var newVal = select.val();
|
||||||
|
|
Loading…
Reference in New Issue