More work

This commit is contained in:
jamesagnew 2014-02-21 21:06:11 -05:00
parent c878922362
commit 668da7b0eb
25 changed files with 3932 additions and 417 deletions

View File

@ -1,56 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="src" path="src/test/java" output="target/test-classes" including="**/*.java"/> <classpathentry kind="src" path="src/test/java" output="target/test-classes" including="**/*.java"/>
<classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/> <classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/>
<classpathentry kind="src" path="src/main/java" including="**/*.java"/> <classpathentry kind="src" path="src/main/java" including="**/*.java"/>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>
<classpathentry kind="var" path="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2.jar" sourcepath="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2-sources.jar"/> <classpathentry kind="var" path="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2.jar" sourcepath="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2-sources.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9-sources.jar">
<classpathentry kind="var" path="M2_REPO/com/google/code/gson/gson/2.2.4/gson-2.2.4.jar" sourcepath="M2_REPO/com/google/code/gson/gson/2.2.4/gson-2.2.4-sources.jar">
<attributes> <attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/com/google/code/gson/gson/2.2.4/gson-2.2.4-javadoc.jar!/" name="javadoc_location"/> <attribute value="jar:file:/Users/james/.m2/repository/commons-codec/commons-codec/1.9/commons-codec-1.9-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0.jar" sourcepath="M2_REPO/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1.jar" sourcepath="M2_REPO/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1.jar" sourcepath="M2_REPO/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.9/commons-codec-1.9-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1.jar" sourcepath="M2_REPO/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1.jar" sourcepath="M2_REPO/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/junit/junit/4.11/junit-4.11.jar" sourcepath="M2_REPO/junit/junit/4.11/junit-4.11-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/junit/junit/4.11/junit-4.11-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" sourcepath="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar">
<attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar!/" name="javadoc_location"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="var" path="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" sourcepath="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2-sources.jar"> <classpathentry kind="var" path="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" sourcepath="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2-sources.jar">
<attributes> <attributes>
<attribute value="jar:file:/home/t3903uhn/.m2/repository/commons-io/commons-io/1.3.2/commons-io-1.3.2-javadoc.jar!/" name="javadoc_location"/> <attribute value="jar:file:/Users/james/.m2/repository/commons-io/commons-io/1.3.2/commons-io-1.3.2-javadoc.jar!/" name="javadoc_location"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1.jar" sourcepath="M2_REPO/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/com/google/code/gson/gson/2.2.4/gson-2.2.4.jar" sourcepath="M2_REPO/com/google/code/gson/gson/2.2.4/gson-2.2.4-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/com/google/code/gson/gson/2.2.4/gson-2.2.4-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" sourcepath="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/junit/junit/4.11/junit-4.11.jar" sourcepath="M2_REPO/junit/junit/4.11/junit-4.11-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/junit/junit/4.11/junit-4.11-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1.jar" sourcepath="M2_REPO/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/ch/qos/logback/logback-classic/1.1.1/logback-classic-1.1.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1.jar" sourcepath="M2_REPO/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/ch/qos/logback/logback-core/1.1.1/logback-core-1.1.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/stax/stax-api/1.0.1/stax-api-1.0.1.jar"/>
<classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1.jar" sourcepath="M2_REPO/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/fasterxml/staxmate/staxmate/2.2.0/staxmate-2.2.0.jar" sourcepath="M2_REPO/com/fasterxml/staxmate/staxmate/2.2.0/staxmate-2.2.0-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/com/fasterxml/staxmate/staxmate/2.2.0/staxmate-2.2.0-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0.jar" sourcepath="M2_REPO/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0-sources.jar">
<attributes>
<attribute value="jar:file:/Users/james/.m2/repository/org/codehaus/woodstox/woodstox-core-asl/4.2.0/woodstox-core-asl-4.2.0-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
</classpath> </classpath>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>hapi-fhir-base</name> <name>hapi-fhir-base</name>
<comment>NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment> <comment>NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment>

View File

@ -22,6 +22,22 @@ public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeChil
myDatatype = theDatatype; myDatatype = theDatatype;
} }
@Override
public String getChildNameByDatatype(Class<? extends IElement> theDatatype) {
if (myDatatype.equals(theDatatype)) {
return getElementName();
}
return null;
}
@Override
public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theDatatype) {
if (myDatatype.equals(theDatatype)) {
return myElementDefinition;
}
return null;
}
@Override @Override
public BaseRuntimeElementDefinition<?> getChildByName(String theName) { public BaseRuntimeElementDefinition<?> getChildByName(String theName) {
if (getElementName().equals(theName)) { if (getElementName().equals(theName)) {

View File

@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.util.BeanUtils; import ca.uhn.fhir.util.BeanUtils;
@ -92,6 +93,10 @@ public abstract class BaseRuntimeChildDefinition {
public abstract Set<String> getValidChildNames(); public abstract Set<String> getValidChildNames();
public abstract String getChildNameByDatatype(Class<? extends IElement> theDatatype);
public abstract BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theType);
abstract void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions); abstract void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions);
private final class ListMutator implements IMutator { private final class ListMutator implements IMutator {
@ -102,10 +107,10 @@ public abstract class BaseRuntimeChildDefinition {
} }
@Override @Override
public void addValue(Object theTarget, Object theValue) { public void addValue(Object theTarget, IElement theValue) {
List<Object> existingList = myAccessor.getValues(theTarget); List<IElement> existingList = myAccessor.getValues(theTarget);
if (existingList == null) { if (existingList == null) {
existingList = new ArrayList<Object>(); existingList = new ArrayList<IElement>();
try { try {
myMutator.invoke(theTarget, existingList); myMutator.invoke(theTarget, existingList);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
@ -129,9 +134,9 @@ public abstract class BaseRuntimeChildDefinition {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public List<Object> getValues(Object theTarget) { public List<IElement> getValues(Object theTarget) {
try { try {
return (List<Object>) myAccessor.invoke(theTarget); return (List<IElement>) myAccessor.invoke(theTarget);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e); throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -152,7 +157,7 @@ public abstract class BaseRuntimeChildDefinition {
} }
@Override @Override
public void addValue(Object theTarget, Object theValue) { public void addValue(Object theTarget, IElement theValue) {
try { try {
if (theValue != null && !myTargetReturnType.isAssignableFrom(theValue.getClass())) { if (theValue != null && !myTargetReturnType.isAssignableFrom(theValue.getClass())) {
throw new ConfigurationException("Value for field " + myElementName + " expects type " + myTargetReturnType + " but got " + theValue.getClass()); throw new ConfigurationException("Value for field " + myElementName + " expects type " + myTargetReturnType + " but got " + theValue.getClass());
@ -176,9 +181,9 @@ public abstract class BaseRuntimeChildDefinition {
} }
@Override @Override
public List<Object> getValues(Object theTarget) { public List<IElement> getValues(Object theTarget) {
try { try {
return Collections.singletonList(myAccessor.invoke(theTarget)); return Collections.singletonList((IElement)myAccessor.invoke(theTarget));
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e); throw new ConfigurationException("Failed to get value", e);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -190,10 +195,10 @@ public abstract class BaseRuntimeChildDefinition {
} }
public interface IMutator { public interface IMutator {
void addValue(Object theTarget, Object theValue); void addValue(Object theTarget, IElement theValue);
} }
public interface IAccessor { public interface IAccessor {
List<Object> getValues(Object theTarget); List<IElement> getValues(Object theTarget);
} }
} }

View File

@ -52,4 +52,8 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IComposite
myChildren = Collections.unmodifiableList(myChildren); myChildren = Collections.unmodifiableList(myChildren);
myNameToChild = Collections.unmodifiableMap(myNameToChild); myNameToChild = Collections.unmodifiableMap(myNameToChild);
} }
public List<BaseRuntimeChildDefinition> getChildren() {
return myChildren;
}
} }

View File

@ -2,6 +2,8 @@ package ca.uhn.fhir.context;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IElement;
public abstract class BaseRuntimeElementDefinition<T extends IElement> { public abstract class BaseRuntimeElementDefinition<T extends IElement> {
@ -10,6 +12,9 @@ public abstract class BaseRuntimeElementDefinition<T extends IElement> {
private Class<? extends T> myImplementingClass; private Class<? extends T> myImplementingClass;
public BaseRuntimeElementDefinition(String theName, Class<? extends T> theImplementingClass) { public BaseRuntimeElementDefinition(String theName, Class<? extends T> theImplementingClass) {
assert StringUtils.isNotBlank(theName);
assert theImplementingClass != null;
myName = theName; myName = theName;
myImplementingClass=theImplementingClass; myImplementingClass=theImplementingClass;
} }
@ -44,7 +49,7 @@ public abstract class BaseRuntimeElementDefinition<T extends IElement> {
public abstract ChildTypeEnum getChildType(); public abstract ChildTypeEnum getChildType();
public enum ChildTypeEnum { public enum ChildTypeEnum {
COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK, PRIMITIVE_XHTML
} }

View File

@ -3,19 +3,26 @@ package ca.uhn.fhir.context;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
public class FhirContext { public class FhirContext {
private final Map<String, RuntimeResourceDefinition> myNameToElementDefinition; private final Map<String, RuntimeResourceDefinition> myNameToElementDefinition;
private Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> myClassToElementDefinition;
public FhirContext(Class<? extends IResource>... theResourceTypes) { public FhirContext(Class<? extends IResource>... theResourceTypes) {
ModelScanner scanner = new ModelScanner(theResourceTypes); ModelScanner scanner = new ModelScanner(theResourceTypes);
myNameToElementDefinition = Collections.unmodifiableMap(scanner.getNameToResourceDefinitions()); myNameToElementDefinition = Collections.unmodifiableMap(scanner.getNameToResourceDefinitions());
myClassToElementDefinition = scanner.getClassToElementDefinitions();
} }
public Map<String, RuntimeResourceDefinition> getNameToResourceDefinition() { public Map<String, RuntimeResourceDefinition> getNameToResourceDefinition() {
return myNameToElementDefinition; return myNameToElementDefinition;
} }
public Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> getClassToElementDefinition() {
return myClassToElementDefinition;
}
} }

View File

@ -36,6 +36,7 @@ import ca.uhn.fhir.model.api.annotation.Narrative;
import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.datatype.ICodedDatatype; import ca.uhn.fhir.model.datatype.ICodedDatatype;
import ca.uhn.fhir.model.datatype.NarrativeDt; import ca.uhn.fhir.model.datatype.NarrativeDt;
import ca.uhn.fhir.model.datatype.XhtmlDt;
class ModelScanner { class ModelScanner {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
@ -89,8 +90,7 @@ class ModelScanner {
ResourceDef resourceDefinition = theClass.getAnnotation(ResourceDef.class); ResourceDef resourceDefinition = theClass.getAnnotation(ResourceDef.class);
if (resourceDefinition != null) { if (resourceDefinition != null) {
if (!IResource.class.isAssignableFrom(theClass)) { if (!IResource.class.isAssignableFrom(theClass)) {
throw new ConfigurationException("Resource type contains a @" + ResourceDef.class.getSimpleName() + " annotation but does not implement " + IResource.class.getCanonicalName() + ": " throw new ConfigurationException("Resource type contains a @" + ResourceDef.class.getSimpleName() + " annotation but does not implement " + IResource.class.getCanonicalName() + ": " + theClass.getCanonicalName());
+ theClass.getCanonicalName());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<? extends IResource> resClass = (Class<? extends IResource>) theClass; Class<? extends IResource> resClass = (Class<? extends IResource>) theClass;
@ -108,8 +108,7 @@ class ModelScanner {
Class<? extends IPrimitiveDatatype<?>> resClass = (Class<? extends IPrimitiveDatatype<?>>) theClass; Class<? extends IPrimitiveDatatype<?>> resClass = (Class<? extends IPrimitiveDatatype<?>>) theClass;
scanPrimitiveDatatype(resClass, datatypeDefinition); scanPrimitiveDatatype(resClass, datatypeDefinition);
} else { } else {
throw new ConfigurationException("Resource type contains a @" + DatatypeDef.class.getSimpleName() + " annotation but does not implement " + IDatatype.class.getCanonicalName() + ": " throw new ConfigurationException("Resource type contains a @" + DatatypeDef.class.getSimpleName() + " annotation but does not implement " + IDatatype.class.getCanonicalName() + ": " + theClass.getCanonicalName());
+ theClass.getCanonicalName());
} }
} }
@ -120,8 +119,7 @@ class ModelScanner {
Class<? extends ICodeEnum> resClass = (Class<? extends ICodeEnum>) theClass; Class<? extends ICodeEnum> resClass = (Class<? extends ICodeEnum>) theClass;
scanCodeTable(resClass, codeTableDefinition); scanCodeTable(resClass, codeTableDefinition);
} else { } else {
throw new ConfigurationException("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());
+ theClass.getCanonicalName());
} }
} }
@ -131,15 +129,13 @@ class ModelScanner {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<? extends IResourceBlock> blockClass = (Class<? extends IResourceBlock>) theClass; Class<? extends IResourceBlock> blockClass = (Class<? extends IResourceBlock>) theClass;
scanBlock(blockClass, blockDefinition); scanBlock(blockClass, blockDefinition);
}else { } else {
throw new ConfigurationException("Type contains a @" + Block.class.getSimpleName() + " annotation but does not implement " + IResourceBlock.class.getCanonicalName() + ": " throw new ConfigurationException("Type contains a @" + Block.class.getSimpleName() + " annotation but does not implement " + IResourceBlock.class.getCanonicalName() + ": " + theClass.getCanonicalName());
+ theClass.getCanonicalName());
} }
} }
if (blockDefinition == null && codeTableDefinition == null && datatypeDefinition == null && resourceDefinition == null) { if (blockDefinition == null && codeTableDefinition == null && datatypeDefinition == null && resourceDefinition == null) {
throw new ConfigurationException("Resource type does not contain any valid HAPI-FHIR annotations: " throw new ConfigurationException("Resource type does not contain any valid HAPI-FHIR annotations: " + theClass.getCanonicalName());
+ theClass.getCanonicalName());
} }
} }
@ -179,7 +175,12 @@ class ModelScanner {
throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theClass.getCanonicalName()); throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theClass.getCanonicalName());
} }
RuntimePrimitiveDatatypeDefinition resourceDef = new RuntimePrimitiveDatatypeDefinition(resourceName, theClass); RuntimePrimitiveDatatypeDefinition resourceDef;
if (theClass.equals(XhtmlDt.class)) {
resourceDef = new RuntimePrimitiveDatatypeNarrativeDefinition(resourceName, theClass);
} else {
resourceDef = new RuntimePrimitiveDatatypeDefinition(resourceName, theClass);
}
myClassToElementDefinitions.put(theClass, resourceDef); myClassToElementDefinitions.put(theClass, resourceDef);
return resourceName; return resourceName;
@ -195,8 +196,7 @@ class ModelScanner {
if (myNameToResourceDefinitions.containsKey(resourceName)) { if (myNameToResourceDefinitions.containsKey(resourceName)) {
if (!myNameToResourceDefinitions.get(resourceName).getImplementingClass().equals(theClass)) { if (!myNameToResourceDefinitions.get(resourceName).getImplementingClass().equals(theClass)) {
throw new ConfigurationException("Detected duplicate element name '" + resourceName + "' in types '" + theClass.getCanonicalName() + "' and '" throw new ConfigurationException("Detected duplicate element name '" + resourceName + "' in types '" + theClass.getCanonicalName() + "' and '" + myNameToResourceDefinitions.get(resourceName).getImplementingClass() + "'");
+ myNameToResourceDefinitions.get(resourceName).getImplementingClass() + "'");
} }
return resourceName; return resourceName;
} }
@ -241,8 +241,7 @@ class ModelScanner {
for (int i = 0; i < orderToElementDef.size(); i++) { for (int i = 0; i < orderToElementDef.size(); i++) {
if (!orderToElementDef.containsKey(i)) { if (!orderToElementDef.containsKey(i)) {
throw new ConfigurationException("Type '" + theClass.getCanonicalName() + "' does not have a child with order " + i throw new ConfigurationException("Type '" + theClass.getCanonicalName() + "' does not have a child with order " + i + " (in other words, there are gaps between specified child orders)");
+ " (in other words, there are gaps between specified child orders)");
} }
BaseRuntimeChildDefinition next = orderToElementDef.get(i); BaseRuntimeChildDefinition next = orderToElementDef.get(i);
theDefinition.addChild(next); theDefinition.addChild(next);
@ -251,8 +250,7 @@ class ModelScanner {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames, private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames, TreeMap<Integer, BaseRuntimeChildDefinition> orderToElementDef) {
TreeMap<Integer, BaseRuntimeChildDefinition> orderToElementDef) {
for (Field next : theClass.getDeclaredFields()) { for (Field next : theClass.getDeclaredFields()) {
Narrative hasNarrative = next.getAnnotation(Narrative.class); Narrative hasNarrative = next.getAnnotation(Narrative.class);
@ -279,8 +277,9 @@ class ModelScanner {
int max = element.max(); int max = element.max();
/* /*
* Anything that's marked as unknown is given a new ID that is <0 so that * Anything that's marked as unknown is given a new ID that is <0 so
* it doesn't conflict wityh any given IDs and can be figured out later * that it doesn't conflict wityh any given IDs and can be figured
* out later
*/ */
while (order == Child.ORDER_UNKNOWN && orderToElementDef.containsKey(order)) { while (order == Child.ORDER_UNKNOWN && orderToElementDef.containsKey(order)) {
order--; order--;
@ -312,7 +311,9 @@ class ModelScanner {
/* /*
* Child is a choice element * Child is a choice element
*/ */
myScanAlso.addAll(choiceTypes); for (Class<? extends IElement> nextType : choiceTypes) {
addScanAlso(nextType);
}
RuntimeChildChoiceDefinition def = new RuntimeChildChoiceDefinition(next, elementName, min, max, choiceTypes); RuntimeChildChoiceDefinition def = new RuntimeChildChoiceDefinition(next, elementName, min, max, choiceTypes);
orderToElementDef.put(order, def); orderToElementDef.put(order, def);
@ -321,13 +322,14 @@ class ModelScanner {
* Child is a resource reference * Child is a resource reference
*/ */
if (resRefAnnotation == null) { if (resRefAnnotation == null) {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is a resource reference but does not have a @" throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is a resource reference but does not have a @" + ChildResource.class.getSimpleName() + " annotation");
+ ChildResource.class.getSimpleName() + " annotation");
} }
Class<? extends IResource>[] refType = resRefAnnotation.types(); Class<? extends IResource>[] refType = resRefAnnotation.types();
List<Class<? extends IResource>> refTypesList = Arrays.asList(refType); List<Class<? extends IResource>> refTypesList = Arrays.asList(refType);
myScanAlso.addAll(refTypesList); for (Class<? extends IElement> nextType : refTypesList) {
addScanAlso(nextType);
}
RuntimeChildResourceDefinition def = new RuntimeChildResourceDefinition(next, elementName, min, max, refTypesList); RuntimeChildResourceDefinition def = new RuntimeChildResourceDefinition(next, elementName, min, max, refTypesList);
orderToElementDef.put(order, def); orderToElementDef.put(order, def);
@ -337,15 +339,15 @@ class ModelScanner {
* TODO: do these have a better name according to HL7? * TODO: do these have a better name according to HL7?
*/ */
Class<? extends IResourceBlock> blockDef = (Class<? extends IResourceBlock>)nextElementType; Class<? extends IResourceBlock> blockDef = (Class<? extends IResourceBlock>) nextElementType;
myScanAlso.add(blockDef); addScanAlso(blockDef);
RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, min, max, elementName, blockDef); RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, min, max, elementName, blockDef);
orderToElementDef.put(order, def); orderToElementDef.put(order, def);
} else if (IDatatype.class.isAssignableFrom(nextElementType)) { } else if (IDatatype.class.isAssignableFrom(nextElementType)) {
Class<? extends IDatatype> nextDatatype = (Class<? extends IDatatype>) nextElementType; Class<? extends IDatatype> nextDatatype = (Class<? extends IDatatype>) nextElementType;
myScanAlso.add(nextDatatype); addScanAlso(nextDatatype);
BaseRuntimeChildDatatypeDefinition def; BaseRuntimeChildDatatypeDefinition def;
if (IPrimitiveDatatype.class.isAssignableFrom(nextElementType)) { if (IPrimitiveDatatype.class.isAssignableFrom(nextElementType)) {
def = new RuntimeChildPrimitiveDatatypeDefinition(next, elementName, min, max, nextDatatype); def = new RuntimeChildPrimitiveDatatypeDefinition(next, elementName, min, max, nextDatatype);
@ -356,8 +358,7 @@ class ModelScanner {
CodeableConceptElement concept = next.getAnnotation(CodeableConceptElement.class); CodeableConceptElement concept = next.getAnnotation(CodeableConceptElement.class);
if (concept != null) { if (concept != null) {
if (!ICodedDatatype.class.isAssignableFrom(nextDatatype)) { if (!ICodedDatatype.class.isAssignableFrom(nextDatatype)) {
throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is marked as @" + CodeableConceptElement.class.getCanonicalName() throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is marked as @" + CodeableConceptElement.class.getCanonicalName() + " but type is not a subtype of " + ICodedDatatype.class.getName());
+ " but type is not a subtype of " + ICodedDatatype.class.getName());
} else { } else {
Class<? extends ICodeEnum> type = concept.type(); Class<? extends ICodeEnum> type = concept.type();
myScanAlsoCodeTable.add(type); myScanAlsoCodeTable.add(type);
@ -376,16 +377,24 @@ class ModelScanner {
} }
} }
private void addScanAlso(Class<? extends IElement> theType) {
if (theType.isInterface()) {
return;
}
myScanAlso.add(theType);
}
private static Class<?> getGenericCollectionTypeOfField(Field next) { private static Class<?> getGenericCollectionTypeOfField(Field next) {
// Type genericSuperclass = next.getType().getGenericSuperclass(); // Type genericSuperclass = next.getType().getGenericSuperclass();
Class<?> type; Class<?> type;
// if (genericSuperclass == null) { // if (genericSuperclass == null) {
ParameterizedType collectionType = (ParameterizedType) next.getGenericType(); ParameterizedType collectionType = (ParameterizedType) next.getGenericType();
type = (Class<?>) collectionType.getActualTypeArguments()[0]; type = (Class<?>) collectionType.getActualTypeArguments()[0];
// }else { // }else {
// Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments(); // Type[] actualTypeArguments = ((ParameterizedType)
// type = (Class<?>) actualTypeArguments[0]; // genericSuperclass).getActualTypeArguments();
// } // type = (Class<?>) actualTypeArguments[0];
// }
return type; return type;
} }
@ -393,4 +402,8 @@ class ModelScanner {
return null; // TODO: implement return null; // TODO: implement
} }
public Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> getClassToElementDefinitions() {
return myClassToElementDefinitions;
}
} }

View File

@ -7,12 +7,15 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IElement;
public class RuntimeChildChoiceDefinition extends BaseRuntimeChildDefinition { public class RuntimeChildChoiceDefinition extends BaseRuntimeChildDefinition {
private List<Class<? extends IElement>> myChoiceTypes; private List<Class<? extends IElement>> myChoiceTypes;
private Map<String, BaseRuntimeElementDefinition<?>> myNameToChildDefinition; private Map<String, BaseRuntimeElementDefinition<?>> myNameToChildDefinition;
private Map<Class<? extends IElement>, String> myDatatypeToElementName;
private Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> myDatatypeToElementDefinition;
public RuntimeChildChoiceDefinition(Field theField, String theElementName, int theMin, int theMax, List<Class<? extends IElement>> theChoiceTypes) { public RuntimeChildChoiceDefinition(Field theField, String theElementName, int theMin, int theMax, List<Class<? extends IElement>> theChoiceTypes) {
super(theField, theMin,theMax, theElementName); super(theField, theMin,theMax, theElementName);
@ -39,11 +42,32 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeChildDefinition {
@Override @Override
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
myNameToChildDefinition = new HashMap<String, BaseRuntimeElementDefinition<?>>(); myNameToChildDefinition = new HashMap<String, BaseRuntimeElementDefinition<?>>();
myDatatypeToElementName = new HashMap<Class<? extends IElement>, String>();
myDatatypeToElementDefinition =new HashMap<Class<? extends IElement>, BaseRuntimeElementDefinition<?>>();
for (Class<? extends IElement> next : myChoiceTypes) { for (Class<? extends IElement> next : myChoiceTypes) {
BaseRuntimeElementDefinition<?> nextDef = theClassToElementDefinitions.get(next); BaseRuntimeElementDefinition<?> nextDef = theClassToElementDefinitions.get(next);
myNameToChildDefinition.put(getElementName() + nextDef.getName(), nextDef); String elementName = getElementName() + nextDef.getName();
myNameToChildDefinition.put(elementName, nextDef);
myDatatypeToElementDefinition.put(next, nextDef);
myDatatypeToElementName.put(next, elementName);
} }
myNameToChildDefinition = Collections.unmodifiableMap(myNameToChildDefinition); myNameToChildDefinition = Collections.unmodifiableMap(myNameToChildDefinition);
myDatatypeToElementName=Collections.unmodifiableMap(myDatatypeToElementName);
myDatatypeToElementDefinition=Collections.unmodifiableMap(myDatatypeToElementDefinition);
}
@Override
public String getChildNameByDatatype(Class<? extends IElement> theDatatype) {
return myDatatypeToElementName.get(theDatatype);
}
@Override
public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theDatatype) {
return myDatatypeToElementDefinition.get(theDatatype);
} }

View File

@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResourceBlock; import ca.uhn.fhir.model.api.IResourceBlock;
@ -27,6 +28,22 @@ public class RuntimeChildResourceBlockDefinition extends BaseRuntimeChildDefinit
} }
} }
@Override
public String getChildNameByDatatype(Class<? extends IElement> theDatatype) {
if (myResourceBlockType.equals(theDatatype)) {
return getElementName();
}
return null;
}
@Override
public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theDatatype) {
if (myResourceBlockType.equals(theDatatype)) {
return myElementDef;
}
return null;
}
@Override @Override
public Set<String> getValidChildNames() { public Set<String> getValidChildNames() {
return Collections.singleton(getElementName()); return Collections.singleton(getElementName());

View File

@ -6,14 +6,35 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceReference;
public class RuntimeChildResourceDefinition extends BaseRuntimeChildDefinition { public class RuntimeChildResourceDefinition extends BaseRuntimeChildDefinition {
private BaseRuntimeElementDefinition<?> myRuntimeDef;
private List<Class<? extends IResource>> myResourceTypes;
public RuntimeChildResourceDefinition(Field theField, String theElementName, int theMin, int theMax, List<Class<? extends IResource>> theChildTypes) { public RuntimeChildResourceDefinition(Field theField, String theElementName, int theMin, int theMax, List<Class<? extends IResource>> theResourceTypes) {
super(theField, theMin, theMax, theElementName); super(theField, theMin, theMax, theElementName);
myResourceTypes = theResourceTypes;
}
@Override
public String getChildNameByDatatype(Class<? extends IElement> theDatatype) {
if (ResourceReference.class.equals(theDatatype)) {
return getElementName();
}
return null;
}
@Override
public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theDatatype) {
if (ResourceReference.class.equals(theDatatype)) {
return myRuntimeDef;
}
return null;
} }
@Override @Override
@ -23,12 +44,11 @@ public class RuntimeChildResourceDefinition extends BaseRuntimeChildDefinition {
@Override @Override
public BaseRuntimeElementDefinition<?> getChildByName(String theName) { public BaseRuntimeElementDefinition<?> getChildByName(String theName) {
return new RuntimeResourceReferenceDefinition(null, null); return myRuntimeDef;
} }
@Override @Override
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
// nothing myRuntimeDef = new RuntimeResourceReferenceDefinition(getElementName(), myResourceTypes);
} }
} }

View File

@ -0,0 +1,16 @@
package ca.uhn.fhir.context;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
public class RuntimePrimitiveDatatypeNarrativeDefinition extends RuntimePrimitiveDatatypeDefinition {
public RuntimePrimitiveDatatypeNarrativeDefinition(String theName, Class<? extends IPrimitiveDatatype<?>> theImplementingClass) {
super(theName, theImplementingClass);
}
@Override
public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
return ChildTypeEnum.PRIMITIVE_XHTML;
}
}

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.context; package ca.uhn.fhir.context;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefinition<IResource> { public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefinition<IResource> {

View File

@ -1,15 +1,17 @@
package ca.uhn.fhir.context; package ca.uhn.fhir.context;
import java.util.List;
import java.util.Map; import java.util.Map;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum; import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceReference;
public class RuntimeResourceReferenceDefinition extends BaseRuntimeElementDefinition<IResource> { public class RuntimeResourceReferenceDefinition extends BaseRuntimeElementDefinition<ResourceReference> {
public RuntimeResourceReferenceDefinition(String theName, Class<? extends IResource> theImplementingClass) { public RuntimeResourceReferenceDefinition(String theName, List<Class<? extends IResource>> theResourceTypes) {
super(theName, theImplementingClass); super(theName, ResourceReference.class);
} }
@Override @Override

View File

@ -1,7 +1,7 @@
package ca.uhn.fhir.model.api; package ca.uhn.fhir.model.api;
public class ResourceReference { public class ResourceReference implements IElement {
private String myDisplay; private String myDisplay;
private String myReference; private String myReference;

View File

@ -1,8 +1,10 @@
package ca.uhn.fhir.model.datatype; package ca.uhn.fhir.model.datatype;
import ca.uhn.fhir.model.api.IPrimitiveDatatype; import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name = "xhtml")
public class XhtmlDt implements IPrimitiveDatatype<String> { public class XhtmlDt implements IPrimitiveDatatype<String> {
private String myValue; private String myValue;

View File

@ -506,7 +506,7 @@ public class Patient extends BaseResource {
* </p> * </p>
*/ */
@Block(name="Patient.contact") @Block(name="Patient.contact")
public static class Contact { public static class Contact implements IResourceBlock {
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED) @Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier; private List<IdentifierDt> myIdentifier;
@ -990,7 +990,7 @@ public class Patient extends BaseResource {
* </p> * </p>
*/ */
@Block(name="Patient.animal") @Block(name="Patient.animal")
public static class Animal { public static class Animal implements IResourceBlock {
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED) @Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier; private List<IdentifierDt> myIdentifier;
@ -1474,7 +1474,7 @@ public class Patient extends BaseResource {
* </p> * </p>
*/ */
@Block(name="Patient.link") @Block(name="Patient.link")
public static class Link { public static class Link implements IResourceBlock {
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED) @Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
private List<IdentifierDt> myIdentifier; private List<IdentifierDt> myIdentifier;

View File

@ -1,5 +1,16 @@
package ca.uhn.fhir.parser; package ca.uhn.fhir.parser;
import java.io.StringWriter;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition; import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
@ -17,84 +28,39 @@ import ca.uhn.fhir.model.api.ResourceReference;
class ParserState { class ParserState {
private enum ResourceReferenceSubState {
INITIAL, REFERENCE, DISPLAY
}
private class ResourceReferenceState extends BaseState {
private ResourceReferenceSubState mySubState;
private RuntimeResourceReferenceDefinition myDefinition;
private ResourceReference myInstance;
public ResourceReferenceState(RuntimeResourceReferenceDefinition theDefinition, ResourceReference theInstance) {
myDefinition = theDefinition;
myInstance = theInstance;
mySubState = ResourceReferenceSubState.INITIAL;
}
@Override
public void attributeValue(String theValue) throws DataFormatException {
switch (mySubState) {
case DISPLAY:
myInstance.setDisplay(theValue);
break;
case INITIAL:
throw new DataFormatException("Unexpected attribute: " + theValue);
case REFERENCE:
myInstance.setReference(theValue);
break;
}
}
@Override
public void enteringNewElement(String theLocalPart) throws DataFormatException {
switch (mySubState) {
case INITIAL:
if ("display".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.DISPLAY;
break;
} else if ("reference".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.REFERENCE;
break;
}
//$FALL-THROUGH$
case DISPLAY:
case REFERENCE:
throw new DataFormatException("Unexpected element: " + theLocalPart);
}
}
@Override
public void endingElement(String theLocalPart) {
switch (mySubState) {
case INITIAL:
pop();
break;
case DISPLAY:
case REFERENCE:
mySubState = ResourceReferenceSubState.INITIAL;
}
}
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
private FhirContext myContext; private FhirContext myContext;
private BaseState myState;
private Object myObject; private Object myObject;
private BaseState myState;
public ParserState(FhirContext theContext) { public ParserState(FhirContext theContext) {
myContext = theContext; myContext = theContext;
} }
public void attributeValue(String theValue) throws DataFormatException { public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
myState.attributeValue(theValue); myState.attributeValue(theAttribute, theValue);
} }
public void enteringNewElement(String theLocalPart) throws DataFormatException { public void endingElement(EndElement theElem) throws DataFormatException {
myState.enteringNewElement(theLocalPart); myState.endingElement(theElem);
}
public void enteringNewElement(StartElement theElement, String theName) throws DataFormatException {
myState.enteringNewElement(theElement, theName);
}
public Object getObject() {
return myObject;
}
public boolean isComplete() {
return myObject != null;
}
private void pop() {
myState = myState.myStack;
} }
private void push(BaseState theState) { private void push(BaseState theState) {
@ -124,15 +90,17 @@ class ParserState {
private abstract class BaseState { private abstract class BaseState {
private BaseState myStack; private BaseState myStack;
public abstract void attributeValue(String theValue) throws DataFormatException; public abstract void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException;
public abstract void enteringNewElement(String theLocalPart) throws DataFormatException; public abstract void endingElement(EndElement theElem) throws DataFormatException;
public abstract void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException;
public void setStack(BaseState theState) { public void setStack(BaseState theState) {
myStack = theState; myStack = theState;
} }
public abstract void endingElement(String theLocalPart); public abstract void otherEvent(XMLEvent theEvent);
} }
@ -147,12 +115,20 @@ class ParserState {
} }
@Override @Override
public void attributeValue(String theValue) { public void attributeValue(Attribute theAttribute, String theValue) {
ourLog.debug("Ignoring attribute value: {}", theValue); ourLog.debug("Ignoring attribute value: {}", theValue);
} }
@Override @Override
public void enteringNewElement(String theChildName) throws DataFormatException { public void endingElement(EndElement theElem) {
pop();
if (myState == null) {
myObject = myInstance;
}
}
@Override
public void enteringNewElement(StartElement theElement, String theChildName) throws DataFormatException {
BaseRuntimeChildDefinition child = myDefinition.getChildByNameOrThrowDataFormatException(theChildName); BaseRuntimeChildDefinition child = myDefinition.getChildByNameOrThrowDataFormatException(theChildName);
BaseRuntimeElementDefinition<?> target = child.getChildByName(theChildName); BaseRuntimeElementDefinition<?> target = child.getChildByName(theChildName);
@ -189,22 +165,18 @@ class ParserState {
push(newState); push(newState);
return; return;
} }
case RESOURCE: case RESOURCE: {
// Throw an exception because this shouldn't happen here // Throw an exception because this shouldn't happen here
break; break;
} }
case PRIMITIVE_XHTML: {
}
}
throw new DataFormatException("Illegal resource position: " + target.getChildType()); throw new DataFormatException("Illegal resource position: " + target.getChildType());
} }
@Override
public void endingElement(String theLocalPart) {
pop();
if (myState == null) {
myObject = myInstance;
}
}
} }
private class PrimitiveState extends BaseState { private class PrimitiveState extends BaseState {
@ -216,36 +188,126 @@ class ParserState {
} }
@Override @Override
public void attributeValue(String theValue) throws DataFormatException { public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
myInstance.setValueAsString(theValue); myInstance.setValueAsString(theValue);
} }
@Override @Override
public void enteringNewElement(String theLocalPart) throws DataFormatException { public void endingElement(EndElement theElem) {
throw new Error("?? can this happen?"); // TODO: can this happen?
}
@Override
public void endingElement(String theLocalPart) {
pop(); pop();
} }
@Override
public void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException {
throw new Error("?? can this happen?"); // TODO: can this happen?
}
} }
public Object getObject() { private class ResourceReferenceState extends BaseState {
return myObject;
private RuntimeResourceReferenceDefinition myDefinition;
private ResourceReference myInstance;
private ResourceReferenceSubState mySubState;
public ResourceReferenceState(RuntimeResourceReferenceDefinition theDefinition, ResourceReference theInstance) {
myDefinition = theDefinition;
myInstance = theInstance;
mySubState = ResourceReferenceSubState.INITIAL;
}
@Override
public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
switch (mySubState) {
case DISPLAY:
myInstance.setDisplay(theValue);
break;
case INITIAL:
throw new DataFormatException("Unexpected attribute: " + theValue);
case REFERENCE:
myInstance.setReference(theValue);
break;
}
}
@Override
public void endingElement(EndElement theElement) {
switch (mySubState) {
case INITIAL:
pop();
break;
case DISPLAY:
case REFERENCE:
mySubState = ResourceReferenceSubState.INITIAL;
}
}
@Override
public void enteringNewElement(StartElement theElem, String theLocalPart) throws DataFormatException {
switch (mySubState) {
case INITIAL:
if ("display".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.DISPLAY;
break;
} else if ("reference".equals(theLocalPart)) {
mySubState = ResourceReferenceSubState.REFERENCE;
break;
}
//$FALL-THROUGH$
case DISPLAY:
case REFERENCE:
throw new DataFormatException("Unexpected element: " + theLocalPart);
}
}
} }
private void pop() { private enum ResourceReferenceSubState {
myState = myState.myStack; DISPLAY, INITIAL, REFERENCE
} }
public boolean isComplete() { private class XhtmlState extends BaseState {
return myObject != null; private StringWriter myStringWriter;
private XMLEventWriter myEventWriter;
private XMLEventFactory myEventFactory;
private XhtmlState() throws DataFormatException {
try {
XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
myStringWriter = new StringWriter();
myEventWriter = xmlFactory.createXMLEventWriter(myStringWriter);
} catch (XMLStreamException e) {
throw new DataFormatException(e);
}
}
@Override
public void attributeValue(Attribute theAttr, String theValue) throws DataFormatException {
try {
myEventWriter.add(theAttr);
} catch (XMLStreamException e) {
throw new DataFormatException(e);
}
}
@Override
public void endingElement(EndElement theElement) throws DataFormatException {
try {
myEventWriter.add(theElement);
} catch (XMLStreamException e) {
throw new DataFormatException(e);
}
}
@Override
public void enteringNewElement(StartElement theElem, String theLocalPart) throws DataFormatException {
// TODO Auto-generated method stub
}
} }
public void endingElement(String theLocalPart) { public void otherEvent(XMLEvent theEvent) {
myState.endingElement(theLocalPart); myState.otherEvent(theEvent);
} }
} }

View File

@ -1,20 +1,35 @@
package ca.uhn.fhir.parser; package ca.uhn.fhir.parser;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.events.Attribute; import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement; import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement; import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent; import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.OutputKeys;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
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.IResource;
import ca.uhn.fhir.model.api.ResourceReference;
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
public class XmlParser { public class XmlParser {
private static final String FHIR_NS = "http://hl7.org/fhir"; private static final String FHIR_NS = "http://hl7.org/fhir";
@ -22,10 +37,89 @@ public class XmlParser {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class);
private FhirContext myContext; private FhirContext myContext;
private XMLInputFactory myXmlInputFactory; private XMLInputFactory myXmlInputFactory;
private XMLOutputFactory myXmlOutputFactory;
public XmlParser(FhirContext theContext) { public XmlParser(FhirContext theContext) {
myContext = theContext; myContext = theContext;
myXmlInputFactory = XMLInputFactory.newInstance(); myXmlInputFactory = XMLInputFactory.newInstance();
myXmlOutputFactory = XMLOutputFactory.newInstance();
}
public String encodeResourceToString(IResource theResource) {
XMLStreamWriter eventWriter;
StringWriter stringWriter = new StringWriter();
try {
eventWriter = myXmlOutputFactory.createXMLStreamWriter(stringWriter);
eventWriter = new PrettyPrintWriterWrapper(eventWriter);
RuntimeResourceDefinition resDef = (RuntimeResourceDefinition) myContext.getClassToElementDefinition().get(theResource.getClass());
eventWriter.writeStartElement(resDef.getName());
eventWriter.writeDefaultNamespace(FHIR_NS);
encodeCompositeElementToStreamWriter(theResource, eventWriter, resDef);
eventWriter.writeEndElement();
eventWriter.close();
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
return stringWriter.toString();
}
private void encodeCompositeElementToStreamWriter(IElement theResource, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws XMLStreamException {
for (BaseRuntimeChildDefinition nextChild : resDef.getChildren()) {
List<IElement> values = nextChild.getAccessor().getValues(theResource);
if (values == null || values.isEmpty()) {
continue;
}
for (IElement nextValue : values) {
if (nextValue == null) {
continue;
}
Class<? extends IElement> type = nextValue.getClass();
String childName = nextChild.getChildNameByDatatype(type);
BaseRuntimeElementDefinition<?> childDef = nextChild.getChildElementDefinitionByDatatype(type);
theEventWriter.writeStartElement(childName);
switch (childDef.getChildType()) {
case PRIMITIVE_DATATYPE: {
IPrimitiveDatatype<?> pd = (IPrimitiveDatatype<?>) nextValue;
theEventWriter.writeAttribute("value", pd.getValueAsString());
break;
}
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> childCompositeDef = (BaseRuntimeElementCompositeDefinition<?>) childDef;
encodeCompositeElementToStreamWriter(nextValue, theEventWriter, childCompositeDef);
break;
}
case RESOURCE_REF: {
ResourceReference ref = (ResourceReference) nextValue;
encodeResourceReferenceToStreamWriter(theEventWriter, ref);
break;
}
case RESOURCE:
throw new IllegalStateException(); // should not happen
}
theEventWriter.writeEndElement();
}
}
}
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, ResourceReference theRef) throws XMLStreamException {
if (StringUtils.isNotBlank(theRef.getDisplay())) {
theEventWriter.writeStartElement("display");
theEventWriter.writeAttribute("value", theRef.getDisplay());
theEventWriter.writeEndElement();
}
if (StringUtils.isNotBlank(theRef.getReference())) {
theEventWriter.writeStartElement("reference");
theEventWriter.writeAttribute("value", theRef.getReference());
theEventWriter.writeEndElement();
}
} }
public IResource parseResource(String theXml) throws ConfigurationException, DataFormatException { public IResource parseResource(String theXml) throws ConfigurationException, DataFormatException {
@ -82,10 +176,12 @@ public class XmlParser {
if (parserState == null) { if (parserState == null) {
throw new DataFormatException("Detected unexpected end-element"); throw new DataFormatException("Detected unexpected end-element");
} }
parserState.endingElement(elem.getName().getLocalPart()); parserState.endingElement(elem);
if (parserState.isComplete()) { if (parserState.isComplete()) {
return (IResource) parserState.getObject(); return (IResource) parserState.getObject();
} }
} else {
parserState.otherEvent(nextEvent);
} }
} }

View File

@ -0,0 +1,226 @@
package ca.uhn.fhir.util;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.commons.lang3.StringUtils;
public class PrettyPrintWriterWrapper implements XMLStreamWriter {
private XMLStreamWriter myTarget;
private int depth = 0;
private Map<Integer, Boolean> hasChildElement = new HashMap<Integer, Boolean>();
private XMLEventFactory myXmlEventFactory;
private static final String INDENT_CHAR = " ";
private static final String LINEFEED_CHAR = "\n";
public PrettyPrintWriterWrapper(XMLStreamWriter target) {
myTarget = target;
}
private String repeat(int d, String s) {
return StringUtils.repeat(s, d * 3);
}
@Override
public void flush() throws XMLStreamException {
myTarget.flush();
}
@Override
public void close() throws XMLStreamException {
myTarget.close();
}
@Override
public String getPrefix(String theUri) throws XMLStreamException {
return myTarget.getPrefix(theUri);
}
@Override
public void setPrefix(String thePrefix, String theUri) throws XMLStreamException {
myTarget.setPrefix(thePrefix, theUri);
}
@Override
public void setDefaultNamespace(String theUri) throws XMLStreamException {
myTarget.setDefaultNamespace(theUri);
}
@Override
public void setNamespaceContext(NamespaceContext theContext) throws XMLStreamException {
myTarget.setNamespaceContext(theContext);
}
@Override
public NamespaceContext getNamespaceContext() {
return myTarget.getNamespaceContext();
}
@Override
public void writeStartElement(String theLocalName) throws XMLStreamException {
indentAndAdd();
myTarget.writeStartElement(theLocalName);
}
private void indentAndAdd() throws XMLStreamException {
indent();
// update state of parent node
if (depth > 0) {
hasChildElement.put(depth - 1, true);
}
// reset state of current node
hasChildElement.put(depth, false);
depth++;
}
private void indent() throws XMLStreamException {
myTarget.writeCharacters(LINEFEED_CHAR + repeat(depth, INDENT_CHAR));
}
@Override
public void writeStartElement(String theNamespaceURI, String theLocalName) throws XMLStreamException {
indentAndAdd();
myTarget.writeStartElement(theNamespaceURI, theLocalName);
}
@Override
public void writeStartElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException {
indentAndAdd();
myTarget.writeStartElement(thePrefix, theNamespaceURI, theLocalName);
}
@Override
public void writeEmptyElement(String theNamespaceURI, String theLocalName) throws XMLStreamException {
indent();
writeEmptyElement(theNamespaceURI, theLocalName);
}
@Override
public void writeEmptyElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException {
indent();
writeEmptyElement(thePrefix, theLocalName, theNamespaceURI);
}
@Override
public void writeEmptyElement(String theLocalName) throws XMLStreamException {
indent();
writeEmptyElement(theLocalName);
}
@Override
public void writeEndElement() throws XMLStreamException {
decrementAndIndent();
myTarget.writeEndElement();
}
private void decrementAndIndent() throws XMLStreamException {
depth--;
if (hasChildElement.get(depth) == true) {
// indent for current depth
myTarget.writeCharacters(LINEFEED_CHAR + repeat(depth, INDENT_CHAR));
}
}
@Override
public void writeEndDocument() throws XMLStreamException {
decrementAndIndent();myTarget.writeEndDocument();
}
@Override
public void writeAttribute(String theLocalName, String theValue) throws XMLStreamException {
myTarget.writeAttribute(theLocalName, theValue);
}
@Override
public void writeAttribute(String thePrefix, String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
myTarget.writeAttribute(thePrefix, theNamespaceURI, theLocalName, theValue);
}
@Override
public void writeAttribute(String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
myTarget.writeAttribute(theNamespaceURI, theLocalName, theValue);
}
@Override
public void writeNamespace(String thePrefix, String theNamespaceURI) throws XMLStreamException {
myTarget.writeNamespace(thePrefix, theNamespaceURI);
}
@Override
public void writeDefaultNamespace(String theNamespaceURI) throws XMLStreamException {
myTarget.writeDefaultNamespace(theNamespaceURI);
}
@Override
public void writeComment(String theData) throws XMLStreamException {
myTarget.writeComment(theData);
}
@Override
public void writeProcessingInstruction(String theTarget) throws XMLStreamException {
myTarget.writeProcessingInstruction(theTarget);
}
@Override
public void writeProcessingInstruction(String theTarget, String theData) throws XMLStreamException {
myTarget.writeProcessingInstruction(theTarget, theData);
}
@Override
public void writeCData(String theData) throws XMLStreamException {
myTarget.writeCData(theData);
}
@Override
public void writeDTD(String theDtd) throws XMLStreamException {
myTarget.writeDTD(theDtd);
}
@Override
public void writeEntityRef(String theName) throws XMLStreamException {
myTarget.writeEntityRef(theName);
}
@Override
public void writeStartDocument() throws XMLStreamException {
myTarget.writeStartDocument();
}
@Override
public void writeStartDocument(String theVersion) throws XMLStreamException {
myTarget.writeStartDocument(theVersion);
}
@Override
public void writeStartDocument(String theEncoding, String theVersion) throws XMLStreamException {
myTarget.writeStartDocument(theEncoding, theVersion);
}
@Override
public void writeCharacters(String theText) throws XMLStreamException {
myTarget.writeCharacters(theText);
}
@Override
public void writeCharacters(char[] theText, int theStart, int theLen) throws XMLStreamException {
myTarget.writeCharacters(theText,theStart,theLen);
}
@Override
public Object getProperty(String theName) throws IllegalArgumentException {
return myTarget.getProperty(theName);
}
}

View File

@ -20,8 +20,8 @@ public class XmlParserTest {
IResource resource = p.parseResource(IOUtils.toString(XmlParserTest.class.getResourceAsStream("/observation-example-eeg.xml"))); IResource resource = p.parseResource(IOUtils.toString(XmlParserTest.class.getResourceAsStream("/observation-example-eeg.xml")));
System.out.println(resource); String result = p.encodeResourceToString(resource);
ourLog.info(result);
} }
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserTest.class);
} }

View File

@ -57,6 +57,10 @@ public class ResourceParser extends BaseParser {
p.setOutputFile("../hapi-fhir-base/src/main/java/ca/uhn/fhir/model/resource/Patient.java"); p.setOutputFile("../hapi-fhir-base/src/main/java/ca/uhn/fhir/model/resource/Patient.java");
p.parse(); p.parse();
p.setResourceName("observation");
p.setOutputFile("../hapi-fhir-base/src/main/java/ca/uhn/fhir/model/resource/Observation.java");
p.parse();
DatatypeParser d = new DatatypeParser(); DatatypeParser d = new DatatypeParser();
d.setDirectory("src/test/resources/dt"); d.setDirectory("src/test/resources/dt");
d.setDatatypeName("humanname"); d.setDatatypeName("humanname");

View File

@ -37,7 +37,7 @@ public class ${className} extends BaseResource {
* </p> * </p>
*/ */
@Block(name="${child.name}") @Block(name="${child.name}")
public static class ${child.className} { public static class ${child.className} implements IResourceBlock {
#childVars( $child.children ) #childVars( $child.children )
#childAccessors( $child.children ) #childAccessors( $child.children )
} }

File diff suppressed because it is too large Load Diff