Parsing observation now works!
This commit is contained in:
parent
d097553f11
commit
3717743cef
|
@ -44,7 +44,7 @@ public abstract class BaseRuntimeElementDefinition<T extends IElement> {
|
|||
public abstract ChildTypeEnum getChildType();
|
||||
|
||||
public enum ChildTypeEnum {
|
||||
COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF
|
||||
COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.lang.reflect.Field;
|
|||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -23,7 +24,9 @@ import ca.uhn.fhir.model.api.IDatatype;
|
|||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
import ca.uhn.fhir.model.api.ResourceReference;
|
||||
import ca.uhn.fhir.model.api.annotation.Block;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.ChildResource;
|
||||
import ca.uhn.fhir.model.api.annotation.Choice;
|
||||
|
@ -77,10 +80,10 @@ class ModelScanner {
|
|||
|
||||
}
|
||||
|
||||
private String scan(Class<? extends IElement> theClass) throws ConfigurationException {
|
||||
private void scan(Class<? extends IElement> theClass) throws ConfigurationException {
|
||||
BaseRuntimeElementDefinition<?> existingDef = myClassToElementDefinitions.get(theClass);
|
||||
if (existingDef != null) {
|
||||
return existingDef.getName();
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceDef resourceDefinition = theClass.getAnnotation(ResourceDef.class);
|
||||
|
@ -91,7 +94,7 @@ class ModelScanner {
|
|||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends IResource> resClass = (Class<? extends IResource>) theClass;
|
||||
return scanResource(resClass, resourceDefinition);
|
||||
scanResource(resClass, resourceDefinition);
|
||||
}
|
||||
|
||||
DatatypeDef datatypeDefinition = theClass.getAnnotation(DatatypeDef.class);
|
||||
|
@ -99,11 +102,11 @@ class ModelScanner {
|
|||
if (ICompositeDatatype.class.isAssignableFrom(theClass)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends ICompositeDatatype> resClass = (Class<? extends ICompositeDatatype>) theClass;
|
||||
return scanCompositeDatatype(resClass, datatypeDefinition);
|
||||
scanCompositeDatatype(resClass, datatypeDefinition);
|
||||
} else if (IPrimitiveDatatype.class.isAssignableFrom(theClass)) {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
Class<? extends IPrimitiveDatatype> resClass = (Class<? extends IPrimitiveDatatype>) theClass;
|
||||
return scanPrimitiveDatatype(resClass, datatypeDefinition);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
Class<? extends IPrimitiveDatatype<?>> resClass = (Class<? extends IPrimitiveDatatype<?>>) theClass;
|
||||
scanPrimitiveDatatype(resClass, datatypeDefinition);
|
||||
} else {
|
||||
throw new ConfigurationException("Resource type contains a @" + DatatypeDef.class.getSimpleName() + " annotation but does not implement " + IDatatype.class.getCanonicalName() + ": "
|
||||
+ theClass.getCanonicalName());
|
||||
|
@ -115,18 +118,46 @@ class ModelScanner {
|
|||
if (ICodeEnum.class.isAssignableFrom(theClass)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends ICodeEnum> resClass = (Class<? extends ICodeEnum>) theClass;
|
||||
return scanCodeTable(resClass, codeTableDefinition);
|
||||
scanCodeTable(resClass, codeTableDefinition);
|
||||
} else {
|
||||
throw new ConfigurationException("Resource type contains a @" + CodeTableDef.class.getSimpleName() + " annotation but does not implement " + ICodeEnum.class.getCanonicalName() + ": "
|
||||
throw new ConfigurationException("Type contains a @" + CodeTableDef.class.getSimpleName() + " annotation but does not implement " + ICodeEnum.class.getCanonicalName() + ": "
|
||||
+ theClass.getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
Block blockDefinition = theClass.getAnnotation(Block.class);
|
||||
if (blockDefinition != null) {
|
||||
if (IResourceBlock.class.isAssignableFrom(theClass)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends IResourceBlock> blockClass = (Class<? extends IResourceBlock>) theClass;
|
||||
scanBlock(blockClass, blockDefinition);
|
||||
}else {
|
||||
throw new ConfigurationException("Type contains a @" + Block.class.getSimpleName() + " annotation but does not implement " + IResourceBlock.class.getCanonicalName() + ": "
|
||||
+ theClass.getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
throw new ConfigurationException("Resource type does not contain a @" + ResourceDef.class.getSimpleName() + " annotation or a @" + DatatypeDef.class.getSimpleName() + " annotation: "
|
||||
+ theClass.getCanonicalName());
|
||||
if (blockDefinition == null && codeTableDefinition == null && datatypeDefinition == null && resourceDefinition == null) {
|
||||
throw new ConfigurationException("Resource type does not contain any valid HAPI-FHIR annotations: "
|
||||
+ theClass.getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
private String scanCompositeDatatype(Class<? extends ICompositeDatatype> theClass, DatatypeDef theDatatypeDefinition) {
|
||||
private void scanBlock(Class<? extends IResourceBlock> theClass, Block theBlockDefinition) {
|
||||
ourLog.debug("Scanning resource block class: {}", theClass.getName());
|
||||
|
||||
String resourceName = theBlockDefinition.name();
|
||||
if (isBlank(resourceName)) {
|
||||
throw new ConfigurationException("Block type @" + Block.class.getSimpleName() + " annotation contains no name: " + theClass.getCanonicalName());
|
||||
}
|
||||
|
||||
RuntimeResourceBlockDefinition resourceDef = new RuntimeResourceBlockDefinition(resourceName, theClass);
|
||||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
|
||||
scanCompositeElementForChildren(theClass, resourceDef, null);
|
||||
}
|
||||
|
||||
private void scanCompositeDatatype(Class<? extends ICompositeDatatype> theClass, DatatypeDef theDatatypeDefinition) {
|
||||
ourLog.debug("Scanning resource class: {}", theClass.getName());
|
||||
|
||||
String resourceName = theDatatypeDefinition.name();
|
||||
|
@ -138,11 +169,9 @@ class ModelScanner {
|
|||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
|
||||
scanCompositeElementForChildren(theClass, resourceDef, null);
|
||||
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
private String scanPrimitiveDatatype(Class<? extends IPrimitiveDatatype> theClass, DatatypeDef theDatatypeDefinition) {
|
||||
private String scanPrimitiveDatatype(Class<? extends IPrimitiveDatatype<?>> theClass, DatatypeDef theDatatypeDefinition) {
|
||||
ourLog.debug("Scanning resource class: {}", theClass.getName());
|
||||
|
||||
String resourceName = theDatatypeDefinition.name();
|
||||
|
@ -201,7 +230,7 @@ class ModelScanner {
|
|||
scanCompositeElementForChildren(next, theDefinition, elementNames, orderToElementDef);
|
||||
}
|
||||
|
||||
while (orderToElementDef.firstKey() < 0) {
|
||||
while (orderToElementDef.size() > 0 && orderToElementDef.firstKey() < 0) {
|
||||
BaseRuntimeChildDefinition elementDef = orderToElementDef.remove(orderToElementDef.firstKey());
|
||||
if (elementDef.getElementName().equals("identifier")) {
|
||||
orderToElementDef.put(theIdentifierOrder, elementDef);
|
||||
|
@ -249,6 +278,10 @@ class ModelScanner {
|
|||
int min = element.min();
|
||||
int max = element.max();
|
||||
|
||||
/*
|
||||
* Anything that's marked as unknown is given a new ID that is <0 so that
|
||||
* it doesn't conflict wityh any given IDs and can be figured out later
|
||||
*/
|
||||
while (order == Child.ORDER_UNKNOWN && orderToElementDef.containsKey(order)) {
|
||||
order--;
|
||||
}
|
||||
|
@ -267,6 +300,13 @@ class ModelScanner {
|
|||
throw new ConfigurationException("Detected duplicate field name '" + elementName + "' in type '" + theClass.getCanonicalName() + "'");
|
||||
}
|
||||
|
||||
Class<?> nextElementType = next.getType();
|
||||
if (List.class.equals(nextElementType)) {
|
||||
nextElementType = getGenericCollectionTypeOfField(next);
|
||||
} else if (Collection.class.isAssignableFrom(nextElementType)) {
|
||||
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is a Collection - Only java.util.List curently supported");
|
||||
}
|
||||
|
||||
ChildResource resRefAnnotation = next.getAnnotation(ChildResource.class);
|
||||
if (choiceTypes.isEmpty() == false) {
|
||||
/*
|
||||
|
@ -276,7 +316,7 @@ class ModelScanner {
|
|||
RuntimeChildChoiceDefinition def = new RuntimeChildChoiceDefinition(next, elementName, min, max, choiceTypes);
|
||||
orderToElementDef.put(order, def);
|
||||
|
||||
} else if (ResourceReference.class.isAssignableFrom(next.getType())) {
|
||||
} else if (ResourceReference.class.isAssignableFrom(nextElementType)) {
|
||||
/*
|
||||
* Child is a resource reference
|
||||
*/
|
||||
|
@ -291,40 +331,23 @@ class ModelScanner {
|
|||
RuntimeChildResourceDefinition def = new RuntimeChildResourceDefinition(next, elementName, min, max, refTypesList);
|
||||
orderToElementDef.put(order, def);
|
||||
|
||||
} else {
|
||||
if (resRefAnnotation != null) {
|
||||
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference but has a @"
|
||||
+ ChildResource.class.getSimpleName() + " annotation");
|
||||
}
|
||||
|
||||
Class<? extends IDatatype> nextDatatype;
|
||||
|
||||
if (IDatatype.class.isAssignableFrom(next.getType())) {
|
||||
nextDatatype = (Class<? extends IDatatype>) next.getType();
|
||||
} else {
|
||||
if (List.class.isAssignableFrom(next.getType())) {
|
||||
|
||||
Class<?> type = getGenericCollectionTypeOfField(next);
|
||||
|
||||
if (IDatatype.class.isAssignableFrom(type)) {
|
||||
nextDatatype = (Class<? extends IDatatype>) type;
|
||||
} else {
|
||||
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type "
|
||||
+ IDatatype.class.getName());
|
||||
}
|
||||
} else {
|
||||
/* TODO: detect when someone has used a different collection (set, etc.) and
|
||||
* give a nice error that indicates that they need to use List..
|
||||
*/
|
||||
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a resource reference and is not an instance of type "
|
||||
+ IDatatype.class.getName());
|
||||
}
|
||||
}
|
||||
} else if (IResourceBlock.class.isAssignableFrom(nextElementType)) {
|
||||
/*
|
||||
* Child is a resource block (i.e. a sub-tag within a resource)
|
||||
* TODO: do these have a better name according to HL7?
|
||||
*/
|
||||
|
||||
Class<? extends IResourceBlock> blockDef = (Class<? extends IResourceBlock>)nextElementType;
|
||||
myScanAlso.add(blockDef);
|
||||
RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, min, max, elementName, blockDef);
|
||||
orderToElementDef.put(order, def);
|
||||
|
||||
} else if (IDatatype.class.isAssignableFrom(nextElementType)) {
|
||||
Class<? extends IDatatype> nextDatatype = (Class<? extends IDatatype>) nextElementType;
|
||||
|
||||
myScanAlso.add(nextDatatype);
|
||||
|
||||
BaseRuntimeChildDatatypeDefinition def;
|
||||
if (IPrimitiveDatatype.class.isAssignableFrom(next.getType())) {
|
||||
if (IPrimitiveDatatype.class.isAssignableFrom(nextElementType)) {
|
||||
def = new RuntimeChildPrimitiveDatatypeDefinition(next, elementName, min, max, nextDatatype);
|
||||
} else {
|
||||
def = new RuntimeChildCompositeDatatypeDefinition(next, elementName, min, max, nextDatatype);
|
||||
|
@ -345,20 +368,8 @@ class ModelScanner {
|
|||
orderToElementDef.put(order, def);
|
||||
|
||||
// TODO: handle codes
|
||||
// if (concept != null) {
|
||||
// Class<? extends ICodeEnum> codeType = concept.type();
|
||||
// String codeTableName = scanCodeTable(codeType);
|
||||
// @SuppressWarnings("unchecked")
|
||||
// String datatypeName = scan((Class<? extends IDatatype>)
|
||||
// next.getType());
|
||||
// RuntimeChildCompositeDatatypeDefinition def = new
|
||||
// RuntimeChildCompositeDatatypeDefinition(next, elementName,
|
||||
// datatypeName, min, max, codeTableName);
|
||||
// orderToElementDef.put(order, def);
|
||||
// } else {
|
||||
// @SuppressWarnings("unchecked")
|
||||
// orderToElementDef.put(order, def);
|
||||
// }
|
||||
} else {
|
||||
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is not a valid child type");
|
||||
}
|
||||
|
||||
elementNames.add(elementName);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
|
||||
public class RuntimeChildResourceBlockDefinition extends BaseRuntimeChildDefinition {
|
||||
|
||||
private RuntimeResourceBlockDefinition myElementDef;
|
||||
private Class<? extends IResourceBlock> myResourceBlockType;
|
||||
|
||||
RuntimeChildResourceBlockDefinition(Field theField, int theMin, int theMax, String theElementName, Class<? extends IResourceBlock> theResourceBlockType) throws ConfigurationException {
|
||||
super(theField, theMin, theMax, theElementName);
|
||||
myResourceBlockType = theResourceBlockType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuntimeResourceBlockDefinition getChildByName(String theName) {
|
||||
if (!getElementName().equals(theName)) {
|
||||
return myElementDef;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getValidChildNames() {
|
||||
return Collections.singleton(getElementName());
|
||||
}
|
||||
|
||||
@Override
|
||||
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||
myElementDef = (RuntimeResourceBlockDefinition) theClassToElementDefinitions.get(myResourceBlockType);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
|
||||
public class RuntimeResourceBlockDefinition extends BaseRuntimeElementCompositeDefinition<IResourceBlock> {
|
||||
|
||||
public RuntimeResourceBlockDefinition(String theName, Class<? extends IResourceBlock> theImplementingClass) {
|
||||
super(theName, theImplementingClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
|
||||
return ChildTypeEnum.RESOURCE_BLOCK;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
public interface IResourceBlock extends ICompositeElement {
|
||||
// nothing yet
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
public class ResourceReference /* <T extends BaseResource> */{
|
||||
|
||||
public class ResourceReference {
|
||||
|
||||
private String myDisplay;
|
||||
private String myReference;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package ca.uhn.fhir.model.api.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value= {ElementType.TYPE})
|
||||
public @interface Block {
|
||||
|
||||
String name();
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import ca.uhn.fhir.model.api.BaseCompositeDatatype;
|
||||
import ca.uhn.fhir.model.api.annotation.Constraint;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
||||
@DatatypeDef(name="Range")
|
||||
public class RangeDt extends BaseCompositeDatatype {
|
||||
|
||||
@Child(name="low", order=0)
|
||||
@Constraint(lessThan= {"high"})
|
||||
private QuantityDt myLow;
|
||||
|
||||
@Child(name="high", order=1)
|
||||
@Constraint(greaterThan= {"low"})
|
||||
private QuantityDt myHigh;
|
||||
|
||||
public QuantityDt getLow() {
|
||||
return myLow;
|
||||
}
|
||||
|
||||
public void setLow(QuantityDt theLow) {
|
||||
myLow = theLow;
|
||||
}
|
||||
|
||||
public QuantityDt getHigh() {
|
||||
return myHigh;
|
||||
}
|
||||
|
||||
public void setHigh(QuantityDt theHigh) {
|
||||
myHigh = theHigh;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package ca.uhn.fhir.model.enm;
|
||||
|
||||
import ca.uhn.fhir.model.api.ICodeEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.EnumeratedCodeValue;
|
||||
import ca.uhn.fhir.model.api.annotation.CodeTableDef;
|
||||
|
||||
@CodeTableDef(tableId = 371, name = "observation-relationshiptype")
|
||||
public enum ObservationRelationshipTypeEnum implements ICodeEnum {
|
||||
|
||||
@EnumeratedCodeValue("has-component")
|
||||
@Description("The target observation is a component of this observation (e.g. Systolic and Diastolic Blood Pressure).")
|
||||
HAS_COMPONENT,
|
||||
|
||||
@EnumeratedCodeValue("has-member")
|
||||
@Description("This observation is a group observation (e.g. a battery, a panel of tests, a set of vital sign measurements) that includes the target as a member of the group.")
|
||||
HAS_MEMBER,
|
||||
|
||||
@EnumeratedCodeValue("derived-from")
|
||||
@Description("The target observation is part of the information from which this observation value is derived (e.g. calculated anion gap, Apgar score).")
|
||||
DERIVED_FROM,
|
||||
|
||||
@EnumeratedCodeValue("sequel-to")
|
||||
@Description("This observation follows the target observation (e.g. timed tests such as Glucose Tolerance Test).")
|
||||
SEQUEL_TO,
|
||||
|
||||
@EnumeratedCodeValue("replaces")
|
||||
@Description("This observation replaces a previous observation (i.e. a revised value). The target observation is now obsolete.")
|
||||
REPLACES,
|
||||
|
||||
@EnumeratedCodeValue("qualified-by")
|
||||
@Description("The value of the target observation qualifies (refines) the semantics of the source observation (e.g. a lipaemia measure target from a plasma measure).")
|
||||
QUALIFIED_BY,
|
||||
|
||||
@EnumeratedCodeValue("interfered-by")
|
||||
@Description("The value of the target observation interferes (degardes quality, or prevents valid observation) with the semantics of the source observation (e.g. a hemolysis measure target from a plasma potassium measure which has no value).")
|
||||
INTERFERED_BY
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package ca.uhn.fhir.model.enm;
|
||||
|
||||
import ca.uhn.fhir.model.api.ICodeEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.CodeTableDef;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.EnumeratedCodeValue;
|
||||
|
||||
@CodeTableDef(tableId = 119, name = "referencerange-meaning")
|
||||
public enum ReferenceRangeMeaningEnum implements ICodeEnum {
|
||||
|
||||
@EnumeratedCodeValue(value = "normal", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Normal Range")
|
||||
NORMAL,
|
||||
|
||||
@EnumeratedCodeValue(value = "recommended", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Recommended Range")
|
||||
RECOMMENDED,
|
||||
|
||||
@EnumeratedCodeValue(value = "treatment", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Treatment Range")
|
||||
TREATMENT,
|
||||
|
||||
@EnumeratedCodeValue(value = "therapeutic", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Therapeutic Desired Level")
|
||||
THERAPEUTIC,
|
||||
|
||||
@EnumeratedCodeValue(value = "pre", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Pre Therapeutic Desired Level")
|
||||
PRE,
|
||||
|
||||
@EnumeratedCodeValue(value = "post", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Post Therapeutic Desired Level")
|
||||
POST,
|
||||
|
||||
@EnumeratedCodeValue(value = "pre-puberty", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Pre-Puberty")
|
||||
PRE_PUBERTY,
|
||||
|
||||
@EnumeratedCodeValue(value = "follicular", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Follicular Stage")
|
||||
FOLLICULAR,
|
||||
|
||||
@EnumeratedCodeValue(value = "midcycle", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("MidCycle")
|
||||
MIDCYCLE,
|
||||
|
||||
@EnumeratedCodeValue(value = "luteal", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Luteal")
|
||||
LUTEAL,
|
||||
|
||||
@EnumeratedCodeValue(value = "postmenopausal", system = "http://hl7.org/fhir/referencerange-meaning")
|
||||
@Description("Post-Menopause")
|
||||
POSTMENOPAUSAL
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package ca.uhn.fhir.model.resource;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
|
||||
@ResourceDef(name="Device")
|
||||
public class Device extends BaseResource {
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package ca.uhn.fhir.model.resource;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
|
||||
@ResourceDef(name="Location")
|
||||
public class Location extends BaseResource {
|
||||
// TODO: populate
|
||||
}
|
|
@ -1,20 +1,24 @@
|
|||
package ca.uhn.fhir.model.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.api.CodeableConceptElement;
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
import ca.uhn.fhir.model.api.ResourceReference;
|
||||
import ca.uhn.fhir.model.api.annotation.Block;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.ChildResource;
|
||||
import ca.uhn.fhir.model.api.annotation.Choice;
|
||||
import ca.uhn.fhir.model.api.annotation.Narrative;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.datatype.AttachmentDt;
|
||||
import ca.uhn.fhir.model.datatype.CodeDt;
|
||||
import ca.uhn.fhir.model.datatype.CodeableConceptDt;
|
||||
import ca.uhn.fhir.model.datatype.DateTimeDt;
|
||||
import ca.uhn.fhir.model.datatype.InstantDt;
|
||||
import ca.uhn.fhir.model.datatype.NarrativeDt;
|
||||
import ca.uhn.fhir.model.datatype.PeriodDt;
|
||||
import ca.uhn.fhir.model.datatype.QuantityDt;
|
||||
import ca.uhn.fhir.model.datatype.RangeDt;
|
||||
import ca.uhn.fhir.model.datatype.RatioDt;
|
||||
import ca.uhn.fhir.model.datatype.SampledDataDt;
|
||||
import ca.uhn.fhir.model.datatype.StringDt;
|
||||
|
@ -22,7 +26,9 @@ import ca.uhn.fhir.model.enm.BodySiteEnum;
|
|||
import ca.uhn.fhir.model.enm.ObservationCodesEnum;
|
||||
import ca.uhn.fhir.model.enm.ObservationInterpretationEnum;
|
||||
import ca.uhn.fhir.model.enm.ObservationMethodEnum;
|
||||
import ca.uhn.fhir.model.enm.ObservationRelationshipTypeEnum;
|
||||
import ca.uhn.fhir.model.enm.ObservationStatusEnum;
|
||||
import ca.uhn.fhir.model.enm.ReferenceRangeMeaningEnum;
|
||||
|
||||
@ResourceDef(name="Observation", identifierOrder=10)
|
||||
public class Observation extends BaseResourceWithIdentifier {
|
||||
|
@ -76,10 +82,111 @@ public class Observation extends BaseResourceWithIdentifier {
|
|||
|
||||
@Child(name="subject", order=11)
|
||||
@ChildResource(types= {
|
||||
Patient.class, Group.class // TODO: add device, location
|
||||
Patient.class, Group.class, Device.class, Location.class
|
||||
})
|
||||
private ResourceReference mySubject;
|
||||
|
||||
@Child(name="specimen", order=12)
|
||||
@ChildResource(types= {
|
||||
Specimen.class
|
||||
})
|
||||
private ResourceReference mySpecimen;
|
||||
|
||||
@Child(name="performer", order=13, max=Child.MAX_UNLIMITED)
|
||||
@ChildResource(types= {
|
||||
Practitioner.class, Device.class, Organization.class
|
||||
})
|
||||
private List<ResourceReference> myPerformer;
|
||||
|
||||
@Child(name="referenceRange", order=14, max=Child.MAX_UNLIMITED)
|
||||
private List<ReferenceRange> myReferenceRange;
|
||||
|
||||
@Child(name="related", order=15, max=Child.MAX_UNLIMITED)
|
||||
private List<Related> myRelated;
|
||||
|
||||
@Block(name="Observation.related")
|
||||
public static class Related implements IResourceBlock
|
||||
{
|
||||
@Child(name="type", order = 0)
|
||||
@CodeableConceptElement(type=ObservationRelationshipTypeEnum.class)
|
||||
private CodeDt<ObservationRelationshipTypeEnum> myType;
|
||||
|
||||
@Child(name="target", order = 1)
|
||||
@ChildResource(types= {
|
||||
Observation.class
|
||||
})
|
||||
private ResourceReference myTarget;
|
||||
|
||||
public CodeDt<ObservationRelationshipTypeEnum> getType() {
|
||||
return myType;
|
||||
}
|
||||
|
||||
public void setType(CodeDt<ObservationRelationshipTypeEnum> theType) {
|
||||
myType = theType;
|
||||
}
|
||||
|
||||
public ResourceReference getTarget() {
|
||||
return myTarget;
|
||||
}
|
||||
|
||||
public void setTarget(ResourceReference theTarget) {
|
||||
myTarget = theTarget;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Block(name="Observation.referenceRange")
|
||||
public static class ReferenceRange implements IResourceBlock
|
||||
{
|
||||
|
||||
@Child(name="low", order=0)
|
||||
private QuantityDt myLow;
|
||||
|
||||
@Child(name="high", order=1)
|
||||
private QuantityDt myHigh;
|
||||
|
||||
@Child(name="meaning", order=2)
|
||||
@CodeableConceptElement(type=ReferenceRangeMeaningEnum.class)
|
||||
private CodeableConceptDt<ReferenceRangeMeaningEnum> myMeaning;
|
||||
|
||||
@Child(name="age", order=3)
|
||||
private RangeDt myAge;
|
||||
|
||||
public QuantityDt getLow() {
|
||||
return myLow;
|
||||
}
|
||||
|
||||
public void setLow(QuantityDt theLow) {
|
||||
myLow = theLow;
|
||||
}
|
||||
|
||||
public QuantityDt getHigh() {
|
||||
return myHigh;
|
||||
}
|
||||
|
||||
public void setHigh(QuantityDt theHigh) {
|
||||
myHigh = theHigh;
|
||||
}
|
||||
|
||||
public CodeableConceptDt<ReferenceRangeMeaningEnum> getMeaning() {
|
||||
return myMeaning;
|
||||
}
|
||||
|
||||
public void setMeaning(CodeableConceptDt<ReferenceRangeMeaningEnum> theMeaning) {
|
||||
myMeaning = theMeaning;
|
||||
}
|
||||
|
||||
public RangeDt getAge() {
|
||||
return myAge;
|
||||
}
|
||||
|
||||
public void setAge(RangeDt theAge) {
|
||||
myAge = theAge;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public CodeableConceptDt<ObservationCodesEnum> getName() {
|
||||
return myName;
|
||||
}
|
||||
|
@ -167,6 +274,38 @@ public class Observation extends BaseResourceWithIdentifier {
|
|||
public void setSubject(ResourceReference theSubject) {
|
||||
mySubject = theSubject;
|
||||
}
|
||||
|
||||
public ResourceReference getSpecimen() {
|
||||
return mySpecimen;
|
||||
}
|
||||
|
||||
public void setSpecimen(ResourceReference theSpecimen) {
|
||||
mySpecimen = theSpecimen;
|
||||
}
|
||||
|
||||
public List<ResourceReference> getPerformer() {
|
||||
return myPerformer;
|
||||
}
|
||||
|
||||
public void setPerformer(List<ResourceReference> thePerformer) {
|
||||
myPerformer = thePerformer;
|
||||
}
|
||||
|
||||
public List<ReferenceRange> getReferenceRange() {
|
||||
return myReferenceRange;
|
||||
}
|
||||
|
||||
public void setReferenceRange(List<ReferenceRange> theReferenceRange) {
|
||||
myReferenceRange = theReferenceRange;
|
||||
}
|
||||
|
||||
public List<Related> getRelated() {
|
||||
return myRelated;
|
||||
}
|
||||
|
||||
public void setRelated(List<Related> theRelated) {
|
||||
myRelated = theRelated;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package ca.uhn.fhir.model.resource;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
|
||||
@ResourceDef(name="Practitioner")
|
||||
public class Practitioner extends BaseResource {
|
||||
// TODO: populate
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package ca.uhn.fhir.model.resource;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
|
||||
@ResourceDef(name="Specimen")
|
||||
public class Specimen extends BaseResource {
|
||||
|
||||
}
|
|
@ -5,12 +5,14 @@ import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
|||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceReferenceDefinition;
|
||||
import ca.uhn.fhir.model.api.ICompositeDatatype;
|
||||
import ca.uhn.fhir.model.api.ICompositeElement;
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
import ca.uhn.fhir.model.api.ResourceReference;
|
||||
|
||||
class ParserState {
|
||||
|
@ -26,7 +28,7 @@ class ParserState {
|
|||
private ResourceReference myInstance;
|
||||
|
||||
public ResourceReferenceState(RuntimeResourceReferenceDefinition theDefinition, ResourceReference theInstance) {
|
||||
myDefinition=theDefinition;
|
||||
myDefinition = theDefinition;
|
||||
myInstance = theInstance;
|
||||
mySubState = ResourceReferenceSubState.INITIAL;
|
||||
}
|
||||
|
@ -38,7 +40,7 @@ class ParserState {
|
|||
myInstance.setDisplay(theValue);
|
||||
break;
|
||||
case INITIAL:
|
||||
throw new DataFormatException("Unexpected attribute: "+theValue);
|
||||
throw new DataFormatException("Unexpected attribute: " + theValue);
|
||||
case REFERENCE:
|
||||
myInstance.setReference(theValue);
|
||||
break;
|
||||
|
@ -56,16 +58,23 @@ class ParserState {
|
|||
mySubState = ResourceReferenceSubState.REFERENCE;
|
||||
break;
|
||||
}
|
||||
// ...else fall through...
|
||||
//$FALL-THROUGH$
|
||||
case DISPLAY:
|
||||
case REFERENCE:
|
||||
throw new DataFormatException("Unexpected element: "+theLocalPart);
|
||||
throw new DataFormatException("Unexpected element: " + theLocalPart);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement(String theLocalPart) {
|
||||
mySubState=ResourceReferenceSubState.INITIAL;
|
||||
switch (mySubState) {
|
||||
case INITIAL:
|
||||
pop();
|
||||
break;
|
||||
case DISPLAY:
|
||||
case REFERENCE:
|
||||
mySubState = ResourceReferenceSubState.INITIAL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,20 +120,22 @@ class ParserState {
|
|||
|
||||
return retVal;
|
||||
}
|
||||
private abstract class BaseState {
|
||||
private BaseState myStack;
|
||||
|
||||
public abstract void attributeValue(String theValue) throws DataFormatException;
|
||||
private abstract class BaseState {
|
||||
private BaseState myStack;
|
||||
|
||||
public abstract void enteringNewElement(String theLocalPart) throws DataFormatException;
|
||||
public abstract void attributeValue(String theValue) throws DataFormatException;
|
||||
|
||||
public abstract void enteringNewElement(String theLocalPart) throws DataFormatException;
|
||||
|
||||
public void setStack(BaseState theState) {
|
||||
myStack = theState;
|
||||
}
|
||||
|
||||
public abstract void endingElement(String theLocalPart);
|
||||
|
||||
public void setStack(BaseState theState) {
|
||||
myStack = theState;
|
||||
}
|
||||
|
||||
public abstract void endingElement(String theLocalPart);
|
||||
|
||||
}
|
||||
private class ContainerState extends BaseState {
|
||||
|
||||
private BaseRuntimeElementCompositeDefinition<?> myDefinition;
|
||||
|
@ -152,15 +163,15 @@ private abstract class BaseState {
|
|||
child.getMutator().addValue(myInstance, newChildInstance);
|
||||
ContainerState newState = new ContainerState(compositeTarget, newChildInstance);
|
||||
push(newState);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
||||
IPrimitiveDatatype<?> newChildInstance = primitiveTarget.newInstance();
|
||||
child.getMutator().addValue(myInstance, newChildInstance);
|
||||
PrimitiveState newState = new PrimitiveState(primitiveTarget, newChildInstance);
|
||||
PrimitiveState newState = new PrimitiveState(newChildInstance);
|
||||
push(newState);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case RESOURCE_REF: {
|
||||
RuntimeResourceReferenceDefinition resourceRefTarget = (RuntimeResourceReferenceDefinition) target;
|
||||
|
@ -168,13 +179,22 @@ private abstract class BaseState {
|
|||
child.getMutator().addValue(myInstance, newChildInstance);
|
||||
ResourceReferenceState newState = new ResourceReferenceState(resourceRefTarget, newChildInstance);
|
||||
push(newState);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case RESOURCE_BLOCK: {
|
||||
RuntimeResourceBlockDefinition blockTarget = (RuntimeResourceBlockDefinition) target;
|
||||
IResourceBlock newBlockInstance = blockTarget.newInstance();
|
||||
child.getMutator().addValue(myInstance, newBlockInstance);
|
||||
ContainerState newState = new ContainerState(blockTarget, newBlockInstance);
|
||||
push(newState);
|
||||
return;
|
||||
}
|
||||
case RESOURCE:
|
||||
default:
|
||||
throw new DataFormatException("Illegal resource position: " + target.getChildType());
|
||||
// Throw an exception because this shouldn't happen here
|
||||
break;
|
||||
}
|
||||
|
||||
throw new DataFormatException("Illegal resource position: " + target.getChildType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,12 +208,10 @@ private abstract class BaseState {
|
|||
}
|
||||
|
||||
private class PrimitiveState extends BaseState {
|
||||
private RuntimePrimitiveDatatypeDefinition myDefinition;
|
||||
private IPrimitiveDatatype<?> myInstance;
|
||||
|
||||
public PrimitiveState(RuntimePrimitiveDatatypeDefinition theDefinition, IPrimitiveDatatype<?> theInstance) {
|
||||
public PrimitiveState(IPrimitiveDatatype<?> theInstance) {
|
||||
super();
|
||||
myDefinition = theDefinition;
|
||||
myInstance = theInstance;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.xml.stream.FactoryConfigurationError;
|
||||
import javax.xml.stream.XMLEventFactory;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
@ -18,15 +18,14 @@ import ca.uhn.fhir.model.api.IResource;
|
|||
|
||||
public class XmlParser {
|
||||
private static final String FHIR_NS = "http://hl7.org/fhir";
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class);
|
||||
private FhirContext myContext;
|
||||
private XMLInputFactory myXmlInputFactory;
|
||||
private XMLEventFactory myEventFactory;
|
||||
|
||||
public XmlParser(FhirContext theContext) {
|
||||
myContext = theContext;
|
||||
myXmlInputFactory = XMLInputFactory.newInstance();
|
||||
myEventFactory = XMLEventFactory.newInstance();
|
||||
}
|
||||
|
||||
public IResource parseResource(String theXml) throws ConfigurationException, DataFormatException {
|
||||
|
@ -54,6 +53,15 @@ public class XmlParser {
|
|||
} else {
|
||||
parserState.enteringNewElement(elem.getName().getLocalPart());
|
||||
}
|
||||
|
||||
for (@SuppressWarnings("unchecked")
|
||||
Iterator<Attribute> iter = elem.getAttributes(); iter.hasNext();) {
|
||||
Attribute next = iter.next();
|
||||
if (next.getName().getLocalPart().equals("value")) {
|
||||
parserState.attributeValue(next.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
} else if (nextEvent.isAttribute()) {
|
||||
Attribute elem = (Attribute) nextEvent;
|
||||
if (!FHIR_NS.equals(elem.getName().getNamespaceURI())) {
|
||||
|
@ -79,10 +87,9 @@ public class XmlParser {
|
|||
return (IResource) parserState.getObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException(e);
|
||||
|
|
Loading…
Reference in New Issue