Parsing observation now works!

This commit is contained in:
jamesagnew 2014-02-20 12:13:05 -05:00
parent d097553f11
commit 3717743cef
17 changed files with 507 additions and 96 deletions

View File

@ -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
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,5 @@
package ca.uhn.fhir.model.api;
public interface IResourceBlock extends ICompositeElement {
// nothing yet
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -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);