Some unit test fixes, still some failures
This commit is contained in:
parent
2c425ca144
commit
79bdd94f72
|
@ -27,6 +27,9 @@ public class FhirContext {
|
||||||
this(toCollection(theResourceType));
|
this(toCollection(theResourceType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FhirContext() {
|
||||||
|
}
|
||||||
|
|
||||||
public FhirContext(Class<?>... theResourceTypes) {
|
public FhirContext(Class<?>... theResourceTypes) {
|
||||||
this(toCollection(theResourceTypes));
|
this(toCollection(theResourceTypes));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,45 @@
|
||||||
package ca.uhn.fhir.model.api;
|
package ca.uhn.fhir.model.api;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
|
||||||
public enum TemporalPrecisionEnum {
|
public enum TemporalPrecisionEnum {
|
||||||
|
|
||||||
YEAR(Calendar.YEAR),
|
YEAR(Calendar.YEAR) {
|
||||||
MONTH(Calendar.MONTH),
|
@Override
|
||||||
DAY(Calendar.DATE),
|
public Date add(Date theInput, int theAmount) {
|
||||||
SECOND(Calendar.SECOND),
|
return DateUtils.addYears(theInput, theAmount);
|
||||||
MILLI(Calendar.MILLISECOND),
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
MONTH(Calendar.MONTH) {
|
||||||
|
@Override
|
||||||
|
public Date add(Date theInput, int theAmount) {
|
||||||
|
return DateUtils.addMonths(theInput, theAmount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DAY(Calendar.DATE) {
|
||||||
|
@Override
|
||||||
|
public Date add(Date theInput, int theAmount) {
|
||||||
|
return DateUtils.addDays(theInput, theAmount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SECOND(Calendar.SECOND) {
|
||||||
|
@Override
|
||||||
|
public Date add(Date theInput, int theAmount) {
|
||||||
|
return DateUtils.addSeconds(theInput, theAmount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
MILLI(Calendar.MILLISECOND) {
|
||||||
|
@Override
|
||||||
|
public Date add(Date theInput, int theAmount) {
|
||||||
|
return DateUtils.addMilliseconds(theInput, theAmount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private int myCalendarConstant;
|
private int myCalendarConstant;
|
||||||
|
@ -17,7 +48,10 @@ public enum TemporalPrecisionEnum {
|
||||||
myCalendarConstant = theCalendarConstant;
|
myCalendarConstant = theCalendarConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract Date add(Date theInput, int theAmount);
|
||||||
|
|
||||||
public int getCalendarConstant() {
|
public int getCalendarConstant() {
|
||||||
return myCalendarConstant;
|
return myCalendarConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ public abstract class BaseParser implements IParser {
|
||||||
public IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException {
|
public IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException {
|
||||||
return parseResource(null, theReader);
|
return parseResource(null, theReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void containResourcesForEncoding(IResource theResource) {
|
public void containResourcesForEncoding(IResource theResource) {
|
||||||
List<ResourceReferenceDt> allElements = theResource.getAllPopulatedChildElementsOfType(ResourceReferenceDt.class);
|
List<ResourceReferenceDt> allElements = theResource.getAllPopulatedChildElementsOfType(ResourceReferenceDt.class);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public interface IParser {
|
||||||
|
|
||||||
<T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString);
|
<T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString);
|
||||||
|
|
||||||
IResource parseResource(Class<? extends IResource> theResourceType, Reader theReader);
|
<T extends IResource> T parseResource(Class<T> theResourceType, Reader theReader);
|
||||||
|
|
||||||
IParser setPrettyPrint(boolean thePrettyPrint);
|
IParser setPrettyPrint(boolean thePrettyPrint);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.io.StringReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -65,21 +66,6 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
return stringWriter.toString();
|
return stringWriter.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
|
|
||||||
if (StringUtils.isNotBlank(theStringDt.getValue())) {
|
|
||||||
theEventWriter.write(theElementName, theStringDt.getValue());
|
|
||||||
} else {
|
|
||||||
theEventWriter.writeNull(theElementName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeOptionalTagWithTextNode(JsonGenerator theEventWriter, String theElementName, IPrimitiveDatatype<?> theInstantDt) {
|
|
||||||
String str = theInstantDt.getValueAsString();
|
|
||||||
if (StringUtils.isNotBlank(str)) {
|
|
||||||
theEventWriter.write(theElementName, theInstantDt.getValueAsString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encodeBundleToWriter(Bundle theBundle, Writer theWriter) throws IOException {
|
public void encodeBundleToWriter(Bundle theBundle, Writer theWriter) throws IOException {
|
||||||
JsonGenerator eventWriter = createJsonGenerator(theWriter);
|
JsonGenerator eventWriter = createJsonGenerator(theWriter);
|
||||||
|
@ -132,26 +118,6 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
eventWriter.close();
|
eventWriter.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAuthor(BaseBundle theBundle, JsonGenerator eventWriter) {
|
|
||||||
if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) {
|
|
||||||
eventWriter.writeStartArray("author");
|
|
||||||
eventWriter.writeStartObject();
|
|
||||||
writeTagWithTextNode(eventWriter, "name", theBundle.getAuthorName());
|
|
||||||
writeOptionalTagWithTextNode(eventWriter, "uri", theBundle.getAuthorUri());
|
|
||||||
eventWriter.writeEnd();
|
|
||||||
eventWriter.writeEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeAtomLink(JsonGenerator theEventWriter, String theRel, StringDt theLink) {
|
|
||||||
if (isNotBlank(theLink.getValue())) {
|
|
||||||
theEventWriter.writeStartObject();
|
|
||||||
theEventWriter.write("rel", theRel);
|
|
||||||
theEventWriter.write("href", theLink.getValue());
|
|
||||||
theEventWriter.writeEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String encodeResourceToString(IResource theResource) throws DataFormatException, IOException {
|
public String encodeResourceToString(IResource theResource) throws DataFormatException, IOException {
|
||||||
Writer stringWriter = new StringWriter();
|
Writer stringWriter = new StringWriter();
|
||||||
|
@ -172,16 +138,6 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonGenerator createJsonGenerator(Writer theWriter) {
|
|
||||||
Map<String, Object> properties = new HashMap<String, Object>(1);
|
|
||||||
if (myPrettyPrint) {
|
|
||||||
properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint);
|
|
||||||
}
|
|
||||||
JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
|
|
||||||
JsonGenerator eventWriter = jgf.createGenerator(theWriter);
|
|
||||||
return eventWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bundle parseBundle(Reader theReader) {
|
public Bundle parseBundle(Reader theReader) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
@ -195,17 +151,22 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IResource parseResource(Class<? extends IResource> theResourceType, Reader theReader) {
|
public <T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString) {
|
||||||
|
return parseResource(theResourceType, new StringReader(theMessageString));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends IResource> T parseResource(Class<T> theResourceType, Reader theReader) {
|
||||||
JsonReader reader = Json.createReader(theReader);
|
JsonReader reader = Json.createReader(theReader);
|
||||||
JsonObject object = reader.readObject();
|
JsonObject object = reader.readObject();
|
||||||
|
|
||||||
JsonValue resourceTypeObj = object.remove("resourceType");
|
JsonValue resourceTypeObj = object.get("resourceType");
|
||||||
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
|
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
|
||||||
String resourceType = ((JsonString)resourceTypeObj).getString();
|
String resourceType = ((JsonString) resourceTypeObj).getString();
|
||||||
|
|
||||||
if (theResourceType != null) {
|
if (theResourceType != null) {
|
||||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
|
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
|
||||||
}else {
|
} else {
|
||||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(resourceType);
|
RuntimeResourceDefinition def = myContext.getResourceDefinition(resourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,25 +200,11 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) {
|
|
||||||
if (theResourceTypeObj.getValueType() != theValueType) {
|
|
||||||
throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IParser setPrettyPrint(boolean thePrettyPrint) {
|
public IParser setPrettyPrint(boolean thePrettyPrint) {
|
||||||
myPrettyPrint = thePrettyPrint;
|
myPrettyPrint = thePrettyPrint;
|
||||||
|
@ -279,6 +226,22 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) {
|
||||||
|
if (theResourceTypeObj.getValueType() != theValueType) {
|
||||||
|
throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonGenerator createJsonGenerator(Writer theWriter) {
|
||||||
|
Map<String, Object> properties = new HashMap<String, Object>(1);
|
||||||
|
if (myPrettyPrint) {
|
||||||
|
properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint);
|
||||||
|
}
|
||||||
|
JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
|
||||||
|
JsonGenerator eventWriter = jgf.createGenerator(theWriter);
|
||||||
|
return eventWriter;
|
||||||
|
}
|
||||||
|
|
||||||
private void encodeChildElementToStreamWriter(JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName) throws IOException {
|
private void encodeChildElementToStreamWriter(JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName) throws IOException {
|
||||||
|
|
||||||
switch (theChildDef.getChildType()) {
|
switch (theChildDef.getChildType()) {
|
||||||
|
@ -318,7 +281,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
if (theChildName != null) {
|
if (theChildName != null) {
|
||||||
theWriter.writeStartObject(theChildName);
|
theWriter.writeStartObject(theChildName);
|
||||||
} else {
|
} else {
|
||||||
theWriter.flush();//TODO: remove
|
theWriter.flush();// TODO: remove
|
||||||
theWriter.writeStartObject();
|
theWriter.writeStartObject();
|
||||||
}
|
}
|
||||||
encodeCompositeElementToStreamWriter(theValue, theWriter, childCompositeDef);
|
encodeCompositeElementToStreamWriter(theValue, theWriter, childCompositeDef);
|
||||||
|
@ -424,7 +387,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
currentChildName = childName;
|
currentChildName = childName;
|
||||||
} else {
|
} else {
|
||||||
theEventWriter.flush();//TODO: remove
|
theEventWriter.flush();// TODO: remove
|
||||||
encodeChildElementToStreamWriter(theEventWriter, nextValue, childDef, null);
|
encodeChildElementToStreamWriter(theEventWriter, nextValue, childDef, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +425,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!haveContent) {
|
if (!haveContent) {
|
||||||
// theEventWriter.writeEnd();
|
// theEventWriter.writeEnd();
|
||||||
theEventWriter.flush(); // TODO: remove
|
theEventWriter.flush(); // TODO: remove
|
||||||
theEventWriter.writeNull();
|
theEventWriter.writeNull();
|
||||||
}
|
}
|
||||||
|
@ -520,7 +483,7 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
theEventWriter.write("resourceType", resDef.getName());
|
theEventWriter.write("resourceType", resDef.getName());
|
||||||
if (theResource.getId() !=null && isNotBlank(theResource.getId().getValue())) {
|
if (theResource.getId() != null && isNotBlank(theResource.getId().getValue())) {
|
||||||
theEventWriter.write("id", theResource.getId().getValue());
|
theEventWriter.write("id", theResource.getId().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,6 +522,41 @@ public class JsonParser extends BaseParser implements IParser {
|
||||||
theWriter.writeEnd();
|
theWriter.writeEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeAtomLink(JsonGenerator theEventWriter, String theRel, StringDt theLink) {
|
||||||
|
if (isNotBlank(theLink.getValue())) {
|
||||||
|
theEventWriter.writeStartObject();
|
||||||
|
theEventWriter.write("rel", theRel);
|
||||||
|
theEventWriter.write("href", theLink.getValue());
|
||||||
|
theEventWriter.writeEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeAuthor(BaseBundle theBundle, JsonGenerator eventWriter) {
|
||||||
|
if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) {
|
||||||
|
eventWriter.writeStartArray("author");
|
||||||
|
eventWriter.writeStartObject();
|
||||||
|
writeTagWithTextNode(eventWriter, "name", theBundle.getAuthorName());
|
||||||
|
writeOptionalTagWithTextNode(eventWriter, "uri", theBundle.getAuthorUri());
|
||||||
|
eventWriter.writeEnd();
|
||||||
|
eventWriter.writeEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeOptionalTagWithTextNode(JsonGenerator theEventWriter, String theElementName, IPrimitiveDatatype<?> theInstantDt) {
|
||||||
|
String str = theInstantDt.getValueAsString();
|
||||||
|
if (StringUtils.isNotBlank(str)) {
|
||||||
|
theEventWriter.write(theElementName, theInstantDt.getValueAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
|
||||||
|
if (StringUtils.isNotBlank(theStringDt.getValue())) {
|
||||||
|
theEventWriter.write(theElementName, theStringDt.getValue());
|
||||||
|
} else {
|
||||||
|
theEventWriter.writeNull(theElementName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class HeldExtension {
|
private class HeldExtension {
|
||||||
|
|
||||||
private UndeclaredExtension myUndeclaredExtension;
|
private UndeclaredExtension myUndeclaredExtension;
|
||||||
|
|
|
@ -115,8 +115,8 @@ class ParserState<T extends IElement> {
|
||||||
* @param theResourceType
|
* @param theResourceType
|
||||||
* May be null
|
* May be null
|
||||||
*/
|
*/
|
||||||
public static ParserState<IResource> getPreResourceInstance(Class<? extends IResource> theResourceType, FhirContext theContext) throws DataFormatException {
|
public static <T extends IResource> ParserState<T> getPreResourceInstance(Class<T> theResourceType, FhirContext theContext) throws DataFormatException {
|
||||||
ParserState<IResource> retVal = new ParserState<IResource>(theContext);
|
ParserState<T> retVal = new ParserState<T>(theContext);
|
||||||
retVal.push(retVal.new PreResourceState(theResourceType));
|
retVal.push(retVal.new PreResourceState(theResourceType));
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,10 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String encodeResourceToString(IResource theResource) throws DataFormatException {
|
public String encodeResourceToString(IResource theResource) throws DataFormatException {
|
||||||
|
if (theResource==null) {
|
||||||
|
throw new NullPointerException("Resource can not be null");
|
||||||
|
}
|
||||||
|
|
||||||
Writer stringWriter = new StringWriter();
|
Writer stringWriter = new StringWriter();
|
||||||
encodeResourceToWriter(theResource, stringWriter);
|
encodeResourceToWriter(theResource, stringWriter);
|
||||||
return stringWriter.toString();
|
return stringWriter.toString();
|
||||||
|
@ -183,7 +187,7 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IResource parseResource(Class<? extends IResource> theResourceType, Reader theReader) {
|
public <T extends IResource> T parseResource(Class<T> theResourceType, Reader theReader) {
|
||||||
XMLEventReader streamReader;
|
XMLEventReader streamReader;
|
||||||
try {
|
try {
|
||||||
streamReader = myXmlInputFactory.createXMLEventReader(theReader);
|
streamReader = myXmlInputFactory.createXMLEventReader(theReader);
|
||||||
|
@ -545,8 +549,8 @@ public class XmlParser extends BaseParser implements IParser {
|
||||||
return doXmlLoop(theStreamReader, parserState);
|
return doXmlLoop(theStreamReader, parserState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IResource parseResource(Class<? extends IResource> theResourceType, XMLEventReader theStreamReader) {
|
private <T extends IResource> T parseResource(Class<T> theResourceType, XMLEventReader theStreamReader) {
|
||||||
ParserState<IResource> parserState = ParserState.getPreResourceInstance(theResourceType, myContext);
|
ParserState<T> parserState = ParserState.getPreResourceInstance(theResourceType, myContext);
|
||||||
return doXmlLoop(theStreamReader, parserState);
|
return doXmlLoop(theStreamReader, parserState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
public class DateRangeParam implements IQueryParameterAnd {
|
public class DateRangeParam implements IQueryParameterAnd {
|
||||||
|
@ -91,13 +92,39 @@ public class DateRangeParam implements IQueryParameterAnd {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getLowerBoundAsInstant() {
|
public Date getLowerBoundAsInstant() {
|
||||||
// TODO: account for precision
|
Date retVal = myLowerBound.getValue();
|
||||||
return myLowerBound.getValue();
|
if (myLowerBound.getComparator() != null) {
|
||||||
|
switch (myLowerBound.getComparator()) {
|
||||||
|
case GREATERTHAN:
|
||||||
|
retVal = myLowerBound.getPrecision().add(retVal, 1);
|
||||||
|
break;
|
||||||
|
case GREATERTHAN_OR_EQUALS:
|
||||||
|
break;
|
||||||
|
case LESSTHAN:
|
||||||
|
case LESSTHAN_OR_EQUALS:
|
||||||
|
throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getComparator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getUpperBoundAsInstant() {
|
public Date getUpperBoundAsInstant() {
|
||||||
// TODO: account for precision
|
Date retVal = myUpperBound.getValue();
|
||||||
return myUpperBound.getValue();
|
if (myUpperBound.getComparator() != null) {
|
||||||
|
switch (myUpperBound.getComparator()) {
|
||||||
|
case LESSTHAN:
|
||||||
|
retVal = new Date(retVal.getTime() - 1L);
|
||||||
|
break;
|
||||||
|
case LESSTHAN_OR_EQUALS:
|
||||||
|
retVal = myUpperBound.getPrecision().add(retVal, 1);
|
||||||
|
retVal = new Date(retVal.getTime() - 1L);
|
||||||
|
break;
|
||||||
|
case GREATERTHAN_OR_EQUALS:
|
||||||
|
case GREATERTHAN:
|
||||||
|
throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getComparator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,7 @@ public class FhirContextIntro {
|
||||||
|
|
||||||
public static void creatingContext() {
|
public static void creatingContext() {
|
||||||
// START SNIPPET: creatingContext
|
// START SNIPPET: creatingContext
|
||||||
/*
|
FhirContext ctx = new FhirContext();
|
||||||
* Create a FhirContex instance which is able to parse and encode
|
|
||||||
* the Patient and Observation resources, and any resources referenced
|
|
||||||
* from these.
|
|
||||||
*/
|
|
||||||
FhirContext ctx = new FhirContext(Patient.class, Observation.class);
|
|
||||||
// END SNIPPET: creatingContext
|
// END SNIPPET: creatingContext
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -103,7 +98,7 @@ StringDt familyName = patient.getName().get(0).getFamily().get(0);
|
||||||
CodeDt gender = patient.getGender().getCoding().get(0).getCode();
|
CodeDt gender = patient.getGender().getCoding().get(0).getCode();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The
|
* The various datatype classes have accessors called getValue()
|
||||||
*/
|
*/
|
||||||
System.out.println(patientId.getValue()); // PRP1660
|
System.out.println(patientId.getValue()); // PRP1660
|
||||||
System.out.println(familyName.getValue()); // Cardinal
|
System.out.println(familyName.getValue()); // Cardinal
|
||||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.rest.annotation.Required;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.client.ITestClient;
|
import ca.uhn.fhir.rest.client.ITestClient;
|
||||||
import ca.uhn.fhir.rest.param.CodingListParam;
|
import ca.uhn.fhir.rest.param.CodingListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
|
||||||
|
@ -161,6 +162,22 @@ public List<DiagnosticReport> getDiagnosticReport( @Required(name=DiagnosticRepo
|
||||||
}
|
}
|
||||||
//END SNIPPET: pathSpec
|
//END SNIPPET: pathSpec
|
||||||
|
|
||||||
|
//START SNIPPET: dateRange
|
||||||
|
@Search()
|
||||||
|
public List<Observation> getObservationsByDateRange(@Required(name="subject.identifier") IdentifierDt theSubjectId,
|
||||||
|
@Required(name=Observation.SP_DATE) DateRangeParam theRange) {
|
||||||
|
List<Observation> retVal = new ArrayList<Observation>();
|
||||||
|
|
||||||
|
// The following two will be set as the start and end
|
||||||
|
// of the range specified by the query parameter
|
||||||
|
Date from = theRange.getLowerBoundAsInstant();
|
||||||
|
Date to = theRange.getUpperBoundAsInstant();
|
||||||
|
|
||||||
|
// ... populate ...
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
//END SNIPPET: dateRange
|
||||||
|
|
||||||
private DiagnosticReport loadSomeDiagnosticReportFromDatabase(IdentifierDt theIdentifier) {
|
private DiagnosticReport loadSomeDiagnosticReportFromDatabase(IdentifierDt theIdentifier) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,15 +159,15 @@
|
||||||
may be optional. To add a second required parameter, annotate the
|
may be optional. To add a second required parameter, annotate the
|
||||||
parameter with
|
parameter with
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Required.html">@Required</a>.
|
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Required.html">@Required</a>.
|
||||||
To add an optional parameter (which will be pased in as <code>null</code> if no value
|
To add an optional parameter (which will be passed in as <code>null</code> if no value
|
||||||
is supplied), annotate the method with
|
is supplied), annotate the method with
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Required.html">@Optional</a>.
|
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Required.html">@Optional</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You may annotate a method with any combination of as many @Required and as many @Optional
|
You may annotate a method with any combination of as many @Required and as many @Optional
|
||||||
parameters as you want. It is valid to have no @Required parameters, or
|
parameters as you want. It is valid to have only @Required parameters, or
|
||||||
no @Optional parameters as well.
|
only @Optional parameters, or any combination of the two.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<macro name="snippet">
|
<macro name="snippet">
|
||||||
|
@ -230,7 +230,7 @@
|
||||||
|
|
||||||
</subsection>
|
</subsection>
|
||||||
|
|
||||||
<subsection name="Date Parameters">
|
<subsection name="Date Parameters - Simple">
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The FHIR specification provides a sytax for specifying
|
The FHIR specification provides a sytax for specifying
|
||||||
|
@ -270,6 +270,46 @@
|
||||||
|
|
||||||
</subsection>
|
</subsection>
|
||||||
|
|
||||||
|
<subsection name="Date Parameters - Ranges">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A common scenario in searches is to allow searching for resources
|
||||||
|
with values (i.e timestamps) within a range of dates.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
FHIR allows for multiple parameters with the same key, and interprets
|
||||||
|
these as being an "AND" set. So, for example, a range of<br/>
|
||||||
|
<code>DATE >= 2011-01-01</code> and <code>DATE < 2011-02-01</code><br/>
|
||||||
|
can be interpreted as any date within January 2011.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following snippet shows how to accept such a range, and combines it
|
||||||
|
with a specific identifier, which is a common scenario. (i.e. Give me a list
|
||||||
|
of observations for a specific patient within a given date range)
|
||||||
|
</p>
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="dateRange" />
|
||||||
|
<param name="file" value="src/site/example/java/example/RestfulPatientResourceProviderMore.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Example URL to invoke this method:<br/>
|
||||||
|
<code>http://fhir.example.com/Observation?subject.identifier=7000135&date=>=2011-01-01&date=<2011-02-01</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Invoking a client of thie type involves the following syntax:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="dateClient" />
|
||||||
|
<param name="file" value="src/site/example/java/example/RestfulPatientResourceProviderMore.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
</subsection>
|
||||||
|
|
||||||
<subsection name="Resource Includes (_include)">
|
<subsection name="Resource Includes (_include)">
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -80,11 +80,13 @@ public class JsonParserTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testSimpleParse() throws DataFormatException, IOException {
|
public void testSimpleParse() throws DataFormatException, IOException {
|
||||||
|
|
||||||
String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/example-patient-general.json"));
|
String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/example-patient-general.json"));
|
||||||
FhirContext ctx = new FhirContext(Patient.class);
|
FhirContext ctx = new FhirContext(Patient.class);
|
||||||
IParser p = ctx.newJsonParser();
|
IParser p = ctx.newJsonParser();
|
||||||
|
ourLog.info("Reading in message: {}", msg);
|
||||||
Patient res = p.parseResource(Patient.class, msg);
|
Patient res = p.parseResource(Patient.class, msg);
|
||||||
|
|
||||||
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
|
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class XmlParserTest {
|
||||||
String str = p.encodeResourceToString(rpt);
|
String str = p.encodeResourceToString(rpt);
|
||||||
|
|
||||||
ourLog.info(str);
|
ourLog.info(str);
|
||||||
assertThat(str, StringContains.containsString("<div>AAA</div>"));
|
assertThat(str, StringContains.containsString("<div xmlns=\"\">AAA</div>"));
|
||||||
assertThat(str, StringContains.containsString("reference value=\"#"));
|
assertThat(str, StringContains.containsString("reference value=\"#"));
|
||||||
|
|
||||||
int idx = str.indexOf("reference value=\"#") + "reference value=\"#".length();
|
int idx = str.indexOf("reference value=\"#") + "reference value=\"#".length();
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
|
public class DateRangeParamTest {
|
||||||
|
|
||||||
|
private static SimpleDateFormat ourFmt;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
ourFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testYear() throws Exception {
|
||||||
|
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011", "<2012").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2012-01-01 00:00:00.0000"), create(">=2011", "<2012").getUpperBoundAsInstant());
|
||||||
|
|
||||||
|
assertEquals(parse("2012-01-01 00:00:00.0000"), create(">2011", "<=2012").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2014-01-01 00:00:00.0000"), create(">2011", "<=2013").getUpperBoundAsInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMonth() throws Exception {
|
||||||
|
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01", "<2011-02").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2011-02-01 00:00:00.0000"), create(">=2011-01", "<2011-02").getUpperBoundAsInstant());
|
||||||
|
|
||||||
|
assertEquals(parse("2011-02-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2011-03-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getUpperBoundAsInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDay() throws Exception {
|
||||||
|
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2011-01-02 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getUpperBoundAsInstant());
|
||||||
|
|
||||||
|
assertEquals(parse("2011-01-02 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2011-01-03 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getUpperBoundAsInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecond() throws Exception {
|
||||||
|
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T01:00:00").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2011-01-01 02:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T02:00:00").getUpperBoundAsInstant());
|
||||||
|
|
||||||
|
assertEquals(parse("2011-01-01 00:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getLowerBoundAsInstant());
|
||||||
|
assertEquals(parseM1("2011-01-01 02:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getUpperBoundAsInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date parse(String theString) throws ParseException {
|
||||||
|
return ourFmt.parse(theString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date parseM1(String theString) throws ParseException {
|
||||||
|
return new Date(ourFmt.parse(theString).getTime() - 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date parseP1(String theString) throws ParseException {
|
||||||
|
return new Date(ourFmt.parse(theString).getTime() + 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException {
|
||||||
|
DateRangeParam p = new DateRangeParam();
|
||||||
|
List<List<String>> tokens=new ArrayList<List<String>>();
|
||||||
|
tokens.add(Collections.singletonList(theLower));
|
||||||
|
tokens.add(Collections.singletonList(theUpper));
|
||||||
|
p.setValuesAsQueryTokens(tokens);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue