Starting on extensions
This commit is contained in:
parent
668da7b0eb
commit
20a705929c
|
@ -9,7 +9,7 @@ import ca.uhn.fhir.model.api.ICodeEnum;
|
|||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
|
||||
public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeChildDefinition {
|
||||
public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeUndeclaredChildDefinition {
|
||||
|
||||
private Class<? extends ICodeEnum> myCodeType;
|
||||
private Class<? extends IDatatype> myDatatype;
|
||||
|
|
|
@ -1,204 +1,32 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.util.BeanUtils;
|
||||
|
||||
public abstract class BaseRuntimeChildDefinition {
|
||||
|
||||
private final IAccessor myAccessor;
|
||||
private final String myElementName;
|
||||
private final Field myField;
|
||||
private final int myMax;
|
||||
private final int myMin;
|
||||
private final IMutator myMutator;
|
||||
|
||||
BaseRuntimeChildDefinition(Field theField, int theMin, int theMax, String theElementName) throws ConfigurationException {
|
||||
super();
|
||||
if (theField == null) {
|
||||
throw new IllegalArgumentException("No field speficied");
|
||||
}
|
||||
if (theMin < 0) {
|
||||
throw new ConfigurationException("Min must be >= 0");
|
||||
}
|
||||
if (theMax != -1 && theMax < theMin) {
|
||||
throw new ConfigurationException("Max must be >= Min (unless it is -1 / unlimited)");
|
||||
}
|
||||
if (isBlank(theElementName)) {
|
||||
throw new ConfigurationException("Element name must not be blank");
|
||||
}
|
||||
|
||||
myField = theField;
|
||||
myMin = theMin;
|
||||
myMax = theMax;
|
||||
myElementName = theElementName;
|
||||
|
||||
// TODO: handle lists (max>0), and maybe max=0?
|
||||
|
||||
Class<?> declaringClass = myField.getDeclaringClass();
|
||||
final Class<?> targetReturnType = myField.getType();
|
||||
try {
|
||||
final Method accessor = BeanUtils.findAccessor(declaringClass, targetReturnType, myElementName);
|
||||
final Method mutator = BeanUtils.findMutator(declaringClass, targetReturnType, myElementName);
|
||||
|
||||
if (List.class.isAssignableFrom(targetReturnType)) {
|
||||
myAccessor = new ListAccessor(accessor);
|
||||
myMutator = new ListMutator(mutator);
|
||||
}else {
|
||||
myAccessor = new PlainAccessor(accessor);
|
||||
myMutator = new PlainMutator(targetReturnType, mutator);
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IAccessor getAccessor() {
|
||||
return myAccessor;
|
||||
}
|
||||
public abstract IAccessor getAccessor();
|
||||
|
||||
public abstract BaseRuntimeElementDefinition<?> getChildByName(String theName);
|
||||
|
||||
public String getElementName() {
|
||||
return myElementName;
|
||||
}
|
||||
|
||||
public Field getField() {
|
||||
return myField;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return myMax;
|
||||
}
|
||||
|
||||
public int getMin() {
|
||||
return myMin;
|
||||
}
|
||||
|
||||
public IMutator getMutator() {
|
||||
return myMutator;
|
||||
}
|
||||
|
||||
public abstract Set<String> getValidChildNames();
|
||||
public abstract BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theType);
|
||||
|
||||
public abstract String getChildNameByDatatype(Class<? extends IElement> theDatatype);
|
||||
|
||||
public abstract BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theType);
|
||||
public abstract IMutator getMutator();
|
||||
|
||||
public abstract Set<String> getValidChildNames();
|
||||
|
||||
abstract void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions);
|
||||
|
||||
private final class ListMutator implements IMutator {
|
||||
private final Method myMutator;
|
||||
|
||||
private ListMutator(Method theMutator) {
|
||||
myMutator = theMutator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addValue(Object theTarget, IElement theValue) {
|
||||
List<IElement> existingList = myAccessor.getValues(theTarget);
|
||||
if (existingList == null) {
|
||||
existingList = new ArrayList<IElement>();
|
||||
try {
|
||||
myMutator.invoke(theTarget, existingList);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
existingList.add(theValue);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ListAccessor implements IAccessor {
|
||||
private final Method myAccessor;
|
||||
|
||||
private ListAccessor(Method theAccessor) {
|
||||
myAccessor = theAccessor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IElement> getValues(Object theTarget) {
|
||||
try {
|
||||
return (List<IElement>) myAccessor.invoke(theTarget);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class PlainMutator implements IMutator {
|
||||
private final Class<?> myTargetReturnType;
|
||||
private final Method myMutator;
|
||||
|
||||
private PlainMutator(Class<?> theTargetReturnType, Method theMutator) {
|
||||
myTargetReturnType = theTargetReturnType;
|
||||
myMutator = theMutator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addValue(Object theTarget, IElement theValue) {
|
||||
try {
|
||||
if (theValue != null && !myTargetReturnType.isAssignableFrom(theValue.getClass())) {
|
||||
throw new ConfigurationException("Value for field " + myElementName + " expects type " + myTargetReturnType + " but got " + theValue.getClass());
|
||||
}
|
||||
myMutator.invoke(theTarget, theValue);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class PlainAccessor implements IAccessor {
|
||||
private final Method myAccessor;
|
||||
|
||||
private PlainAccessor(Method theAccessor) {
|
||||
myAccessor = theAccessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IElement> getValues(Object theTarget) {
|
||||
try {
|
||||
return Collections.singletonList((IElement)myAccessor.invoke(theTarget));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
public interface IAccessor {
|
||||
List<? extends IElement> getValues(Object theTarget);
|
||||
}
|
||||
|
||||
public interface IMutator {
|
||||
void addValue(Object theTarget, IElement theValue);
|
||||
}
|
||||
|
||||
public interface IAccessor {
|
||||
List<IElement> getValues(Object theTarget);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public abstract class BaseRuntimeElementDefinition<T extends IElement> {
|
|||
public abstract ChildTypeEnum getChildType();
|
||||
|
||||
public enum ChildTypeEnum {
|
||||
COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK, PRIMITIVE_XHTML
|
||||
COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK, PRIMITIVE_XHTML, UNDECL_EXT
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.util.BeanUtils;
|
||||
|
||||
public abstract class BaseRuntimeUndeclaredChildDefinition extends BaseRuntimeChildDefinition {
|
||||
|
||||
private final IAccessor myAccessor;
|
||||
private final String myElementName;
|
||||
private final Field myField;
|
||||
private final int myMax;
|
||||
private final int myMin;
|
||||
private final IMutator myMutator;
|
||||
|
||||
BaseRuntimeUndeclaredChildDefinition(Field theField, int theMin, int theMax, String theElementName) throws ConfigurationException {
|
||||
super();
|
||||
if (theField == null) {
|
||||
throw new IllegalArgumentException("No field speficied");
|
||||
}
|
||||
if (theMin < 0) {
|
||||
throw new ConfigurationException("Min must be >= 0");
|
||||
}
|
||||
if (theMax != -1 && theMax < theMin) {
|
||||
throw new ConfigurationException("Max must be >= Min (unless it is -1 / unlimited)");
|
||||
}
|
||||
if (isBlank(theElementName)) {
|
||||
throw new ConfigurationException("Element name must not be blank");
|
||||
}
|
||||
|
||||
myField = theField;
|
||||
myMin = theMin;
|
||||
myMax = theMax;
|
||||
myElementName = theElementName;
|
||||
|
||||
// TODO: handle lists (max>0), and maybe max=0?
|
||||
|
||||
Class<?> declaringClass = myField.getDeclaringClass();
|
||||
final Class<?> targetReturnType = myField.getType();
|
||||
try {
|
||||
final Method accessor = BeanUtils.findAccessor(declaringClass, targetReturnType, myElementName);
|
||||
final Method mutator = BeanUtils.findMutator(declaringClass, targetReturnType, myElementName);
|
||||
|
||||
if (List.class.isAssignableFrom(targetReturnType)) {
|
||||
myAccessor = new ListAccessor(accessor);
|
||||
myMutator = new ListMutator(mutator);
|
||||
}else {
|
||||
myAccessor = new PlainAccessor(accessor);
|
||||
myMutator = new PlainMutator(targetReturnType, mutator);
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IAccessor getAccessor() {
|
||||
return myAccessor;
|
||||
}
|
||||
|
||||
public String getElementName() {
|
||||
return myElementName;
|
||||
}
|
||||
|
||||
public Field getField() {
|
||||
return myField;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return myMax;
|
||||
}
|
||||
|
||||
public int getMin() {
|
||||
return myMin;
|
||||
}
|
||||
|
||||
public IMutator getMutator() {
|
||||
return myMutator;
|
||||
}
|
||||
|
||||
private final class ListMutator implements IMutator {
|
||||
private final Method myMutator;
|
||||
|
||||
private ListMutator(Method theMutator) {
|
||||
myMutator = theMutator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addValue(Object theTarget, IElement theValue) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<IElement> existingList = (List<IElement>) myAccessor.getValues(theTarget);
|
||||
if (existingList == null) {
|
||||
existingList = new ArrayList<IElement>();
|
||||
try {
|
||||
myMutator.invoke(theTarget, existingList);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
existingList.add(theValue);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ListAccessor implements IAccessor {
|
||||
private final Method myAccessor;
|
||||
|
||||
private ListAccessor(Method theAccessor) {
|
||||
myAccessor = theAccessor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IElement> getValues(Object theTarget) {
|
||||
try {
|
||||
return (List<IElement>) myAccessor.invoke(theTarget);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class PlainMutator implements IMutator {
|
||||
private final Class<?> myTargetReturnType;
|
||||
private final Method myMutator;
|
||||
|
||||
private PlainMutator(Class<?> theTargetReturnType, Method theMutator) {
|
||||
myTargetReturnType = theTargetReturnType;
|
||||
myMutator = theMutator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addValue(Object theTarget, IElement theValue) {
|
||||
try {
|
||||
if (theValue != null && !myTargetReturnType.isAssignableFrom(theValue.getClass())) {
|
||||
throw new ConfigurationException("Value for field " + myElementName + " expects type " + myTargetReturnType + " but got " + theValue.getClass());
|
||||
}
|
||||
myMutator.invoke(theTarget, theValue);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class PlainAccessor implements IAccessor {
|
||||
private final Method myAccessor;
|
||||
|
||||
private PlainAccessor(Method theAccessor) {
|
||||
myAccessor = theAccessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IElement> getValues(Object theTarget) {
|
||||
try {
|
||||
return Collections.singletonList((IElement)myAccessor.invoke(theTarget));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigurationException("Failed to get value", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -10,11 +10,17 @@ public class FhirContext {
|
|||
|
||||
private final Map<String, RuntimeResourceDefinition> myNameToElementDefinition;
|
||||
private Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> myClassToElementDefinition;
|
||||
private RuntimeChildUndeclaredExtensionDefinition myRuntimeChildUndeclaredExtensionDefinition;
|
||||
|
||||
public FhirContext(Class<? extends IResource>... theResourceTypes) {
|
||||
ModelScanner scanner = new ModelScanner(theResourceTypes);
|
||||
myNameToElementDefinition = Collections.unmodifiableMap(scanner.getNameToResourceDefinitions());
|
||||
myClassToElementDefinition = scanner.getClassToElementDefinitions();
|
||||
myClassToElementDefinition = Collections.unmodifiableMap(scanner.getClassToElementDefinitions());
|
||||
myRuntimeChildUndeclaredExtensionDefinition = scanner.getRuntimeChildUndeclaredExtensionDefinition();
|
||||
}
|
||||
|
||||
public RuntimeChildUndeclaredExtensionDefinition getRuntimeChildUndeclaredExtensionDefinition() {
|
||||
return myRuntimeChildUndeclaredExtensionDefinition;
|
||||
}
|
||||
|
||||
public Map<String, RuntimeResourceDefinition> getNameToResourceDefinition() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
@ -34,6 +34,8 @@ import ca.uhn.fhir.model.api.annotation.CodeTableDef;
|
|||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.Narrative;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.datatype.CodeDt;
|
||||
import ca.uhn.fhir.model.datatype.DateDt;
|
||||
import ca.uhn.fhir.model.datatype.ICodedDatatype;
|
||||
import ca.uhn.fhir.model.datatype.NarrativeDt;
|
||||
import ca.uhn.fhir.model.datatype.XhtmlDt;
|
||||
|
@ -42,22 +44,24 @@ class ModelScanner {
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
|
||||
|
||||
private Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> myClassToElementDefinitions = new HashMap<Class<? extends IElement>, BaseRuntimeElementDefinition<?>>();
|
||||
private Map<String, BaseRuntimeElementDefinition<?>> myDatatypeAttributeNameToDefinition = new HashMap<String, BaseRuntimeElementDefinition<?>>();
|
||||
private Map<String, RuntimeResourceDefinition> myNameToResourceDefinitions = new HashMap<String, RuntimeResourceDefinition>();
|
||||
private Set<Class<? extends IElement>> myScanAlso = new HashSet<Class<? extends IElement>>();
|
||||
private Set<Class<? extends ICodeEnum>> myScanAlsoCodeTable = new HashSet<Class<? extends ICodeEnum>>();
|
||||
|
||||
// private Map<String, RuntimeResourceDefinition>
|
||||
// myNameToDatatypeDefinitions = new HashMap<String,
|
||||
// RuntimeDatatypeDefinition>();
|
||||
|
||||
public Map<String, RuntimeResourceDefinition> getNameToResourceDefinitions() {
|
||||
return (myNameToResourceDefinitions);
|
||||
}
|
||||
private Set<Class<? extends ICodeEnum>> myScanAlsoCodeTable = new HashSet<Class<? extends ICodeEnum>>();
|
||||
|
||||
private RuntimeChildUndeclaredExtensionDefinition myRuntimeChildUndeclaredExtensionDefinition;
|
||||
|
||||
ModelScanner(Class<? extends IResource>... theResourceTypes) throws ConfigurationException {
|
||||
|
||||
Set<Class<? extends IElement>> toScan = new HashSet<Class<? extends IElement>>(Arrays.asList(theResourceTypes));
|
||||
toScan.add(NarrativeDt.class);
|
||||
toScan.add(DateDt.class);
|
||||
toScan.add(CodeDt.class);
|
||||
|
||||
do {
|
||||
for (Class<? extends IElement> nextClass : toScan) {
|
||||
|
@ -77,10 +81,41 @@ class ModelScanner {
|
|||
next.sealAndInitialize(myClassToElementDefinitions);
|
||||
}
|
||||
|
||||
myRuntimeChildUndeclaredExtensionDefinition = new RuntimeChildUndeclaredExtensionDefinition(myDatatypeAttributeNameToDefinition);
|
||||
|
||||
ourLog.info("Done scanning FHIR library, found {} model entries", myClassToElementDefinitions.size());
|
||||
|
||||
}
|
||||
|
||||
public RuntimeChildUndeclaredExtensionDefinition getRuntimeChildUndeclaredExtensionDefinition() {
|
||||
return myRuntimeChildUndeclaredExtensionDefinition;
|
||||
}
|
||||
|
||||
public Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> getClassToElementDefinitions() {
|
||||
return myClassToElementDefinitions;
|
||||
}
|
||||
|
||||
public Map<String, RuntimeResourceDefinition> getNameToResourceDefinitions() {
|
||||
return (myNameToResourceDefinitions);
|
||||
}
|
||||
|
||||
private void addDatatype(BaseRuntimeElementDefinition<?> theResourceDef) {
|
||||
String attrName = theResourceDef.getName();
|
||||
attrName = "value" + attrName.substring(0, 1).toUpperCase() + attrName.substring(1);
|
||||
myDatatypeAttributeNameToDefinition.put(attrName, theResourceDef);
|
||||
}
|
||||
|
||||
private void addScanAlso(Class<? extends IElement> theType) {
|
||||
if (theType.isInterface()) {
|
||||
return;
|
||||
}
|
||||
myScanAlso.add(theType);
|
||||
}
|
||||
|
||||
public Map<String, BaseRuntimeElementDefinition<?>> getDatatypeAttributeNameToDefinition() {
|
||||
return myDatatypeAttributeNameToDefinition;
|
||||
}
|
||||
|
||||
private void scan(Class<? extends IElement> theClass) throws ConfigurationException {
|
||||
BaseRuntimeElementDefinition<?> existingDef = myClassToElementDefinitions.get(theClass);
|
||||
if (existingDef != null) {
|
||||
|
@ -153,6 +188,10 @@ class ModelScanner {
|
|||
scanCompositeElementForChildren(theClass, resourceDef, null);
|
||||
}
|
||||
|
||||
private String scanCodeTable(Class<? extends ICodeEnum> theCodeType, CodeTableDef theCodeTableDefinition) {
|
||||
return null; // TODO: implement
|
||||
}
|
||||
|
||||
private void scanCompositeDatatype(Class<? extends ICompositeDatatype> theClass, DatatypeDef theDatatypeDefinition) {
|
||||
ourLog.debug("Scanning resource class: {}", theClass.getName());
|
||||
|
||||
|
@ -163,57 +202,15 @@ class ModelScanner {
|
|||
|
||||
RuntimeCompositeDatatypeDefinition resourceDef = new RuntimeCompositeDatatypeDefinition(resourceName, theClass);
|
||||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
addDatatype(resourceDef);
|
||||
|
||||
scanCompositeElementForChildren(theClass, resourceDef, null);
|
||||
}
|
||||
|
||||
private String scanPrimitiveDatatype(Class<? extends IPrimitiveDatatype<?>> theClass, DatatypeDef theDatatypeDefinition) {
|
||||
ourLog.debug("Scanning resource class: {}", theClass.getName());
|
||||
|
||||
String resourceName = theDatatypeDefinition.name();
|
||||
if (isBlank(resourceName)) {
|
||||
throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theClass.getCanonicalName());
|
||||
}
|
||||
|
||||
RuntimePrimitiveDatatypeDefinition resourceDef;
|
||||
if (theClass.equals(XhtmlDt.class)) {
|
||||
resourceDef = new RuntimePrimitiveDatatypeNarrativeDefinition(resourceName, theClass);
|
||||
} else {
|
||||
resourceDef = new RuntimePrimitiveDatatypeDefinition(resourceName, theClass);
|
||||
}
|
||||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
private String scanResource(Class<? extends IResource> theClass, ResourceDef resourceDefinition) {
|
||||
ourLog.debug("Scanning resource class: {}", theClass.getName());
|
||||
|
||||
String resourceName = resourceDefinition.name();
|
||||
if (isBlank(resourceName)) {
|
||||
throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theClass.getCanonicalName());
|
||||
}
|
||||
|
||||
if (myNameToResourceDefinitions.containsKey(resourceName)) {
|
||||
if (!myNameToResourceDefinitions.get(resourceName).getImplementingClass().equals(theClass)) {
|
||||
throw new ConfigurationException("Detected duplicate element name '" + resourceName + "' in types '" + theClass.getCanonicalName() + "' and '" + myNameToResourceDefinitions.get(resourceName).getImplementingClass() + "'");
|
||||
}
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resourceDef = new RuntimeResourceDefinition(theClass, resourceName);
|
||||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
myNameToResourceDefinitions.put(resourceName, resourceDef);
|
||||
|
||||
scanCompositeElementForChildren(theClass, resourceDef, resourceDefinition.identifierOrder());
|
||||
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Integer theIdentifierOrder) {
|
||||
Set<String> elementNames = new HashSet<String>();
|
||||
TreeMap<Integer, BaseRuntimeChildDefinition> orderToElementDef = new TreeMap<Integer, BaseRuntimeChildDefinition>();
|
||||
TreeMap<Integer, BaseRuntimeUndeclaredChildDefinition> orderToElementDef = new TreeMap<Integer, BaseRuntimeUndeclaredChildDefinition>();
|
||||
|
||||
LinkedList<Class<? extends ICompositeElement>> classes = new LinkedList<Class<? extends ICompositeElement>>();
|
||||
Class<? extends ICompositeElement> current = theClass;
|
||||
|
@ -231,7 +228,7 @@ class ModelScanner {
|
|||
}
|
||||
|
||||
while (orderToElementDef.size() > 0 && orderToElementDef.firstKey() < 0) {
|
||||
BaseRuntimeChildDefinition elementDef = orderToElementDef.remove(orderToElementDef.firstKey());
|
||||
BaseRuntimeUndeclaredChildDefinition elementDef = orderToElementDef.remove(orderToElementDef.firstKey());
|
||||
if (elementDef.getElementName().equals("identifier")) {
|
||||
orderToElementDef.put(theIdentifierOrder, elementDef);
|
||||
} else {
|
||||
|
@ -250,7 +247,7 @@ class ModelScanner {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames, TreeMap<Integer, BaseRuntimeChildDefinition> orderToElementDef) {
|
||||
private void scanCompositeElementForChildren(Class<? extends ICompositeElement> theClass, BaseRuntimeElementCompositeDefinition<?> theDefinition, Set<String> elementNames, TreeMap<Integer, BaseRuntimeUndeclaredChildDefinition> orderToElementDef) {
|
||||
for (Field next : theClass.getDeclaredFields()) {
|
||||
|
||||
Narrative hasNarrative = next.getAnnotation(Narrative.class);
|
||||
|
@ -377,11 +374,50 @@ class ModelScanner {
|
|||
}
|
||||
}
|
||||
|
||||
private void addScanAlso(Class<? extends IElement> theType) {
|
||||
if (theType.isInterface()) {
|
||||
return;
|
||||
private String scanPrimitiveDatatype(Class<? extends IPrimitiveDatatype<?>> theClass, DatatypeDef theDatatypeDefinition) {
|
||||
ourLog.debug("Scanning resource class: {}", theClass.getName());
|
||||
|
||||
String resourceName = theDatatypeDefinition.name();
|
||||
if (isBlank(resourceName)) {
|
||||
throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theClass.getCanonicalName());
|
||||
}
|
||||
myScanAlso.add(theType);
|
||||
|
||||
BaseRuntimeElementDefinition<?> resourceDef;
|
||||
if (theClass.equals(XhtmlDt.class)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<XhtmlDt> clazz = (Class<XhtmlDt>) theClass;
|
||||
resourceDef = new RuntimePrimitiveDatatypeNarrativeDefinition(resourceName, clazz);
|
||||
} else {
|
||||
resourceDef = new RuntimePrimitiveDatatypeDefinition(resourceName, theClass);
|
||||
}
|
||||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
addDatatype(resourceDef);
|
||||
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
private String scanResource(Class<? extends IResource> theClass, ResourceDef resourceDefinition) {
|
||||
ourLog.debug("Scanning resource class: {}", theClass.getName());
|
||||
|
||||
String resourceName = resourceDefinition.name();
|
||||
if (isBlank(resourceName)) {
|
||||
throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theClass.getCanonicalName());
|
||||
}
|
||||
|
||||
if (myNameToResourceDefinitions.containsKey(resourceName)) {
|
||||
if (!myNameToResourceDefinitions.get(resourceName).getImplementingClass().equals(theClass)) {
|
||||
throw new ConfigurationException("Detected duplicate element name '" + resourceName + "' in types '" + theClass.getCanonicalName() + "' and '" + myNameToResourceDefinitions.get(resourceName).getImplementingClass() + "'");
|
||||
}
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resourceDef = new RuntimeResourceDefinition(theClass, resourceName);
|
||||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
myNameToResourceDefinitions.put(resourceName, resourceDef);
|
||||
|
||||
scanCompositeElementForChildren(theClass, resourceDef, resourceDefinition.identifierOrder());
|
||||
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
private static Class<?> getGenericCollectionTypeOfField(Field next) {
|
||||
|
@ -398,12 +434,4 @@ class ModelScanner {
|
|||
return type;
|
||||
}
|
||||
|
||||
private String scanCodeTable(Class<? extends ICodeEnum> theCodeType, CodeTableDef theCodeTableDefinition) {
|
||||
return null; // TODO: implement
|
||||
}
|
||||
|
||||
public Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> getClassToElementDefinitions() {
|
||||
return myClassToElementDefinitions;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import java.util.Set;
|
|||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
|
||||
public class RuntimeChildChoiceDefinition extends BaseRuntimeChildDefinition {
|
||||
public class RuntimeChildChoiceDefinition extends BaseRuntimeUndeclaredChildDefinition {
|
||||
|
||||
private List<Class<? extends IElement>> myChoiceTypes;
|
||||
private Map<String, BaseRuntimeElementDefinition<?>> myNameToChildDefinition;
|
||||
|
|
|
@ -9,7 +9,7 @@ import ca.uhn.fhir.model.api.IDatatype;
|
|||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
|
||||
public class RuntimeChildResourceBlockDefinition extends BaseRuntimeChildDefinition {
|
||||
public class RuntimeChildResourceBlockDefinition extends BaseRuntimeUndeclaredChildDefinition {
|
||||
|
||||
private RuntimeResourceBlockDefinition myElementDef;
|
||||
private Class<? extends IResourceBlock> myResourceBlockType;
|
||||
|
|
|
@ -11,7 +11,7 @@ import ca.uhn.fhir.model.api.IElement;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceReference;
|
||||
|
||||
public class RuntimeChildResourceDefinition extends BaseRuntimeChildDefinition {
|
||||
public class RuntimeChildResourceDefinition extends BaseRuntimeUndeclaredChildDefinition {
|
||||
|
||||
private BaseRuntimeElementDefinition<?> myRuntimeDef;
|
||||
private List<Class<? extends IResource>> myResourceTypes;
|
||||
|
@ -49,6 +49,6 @@ public class RuntimeChildResourceDefinition extends BaseRuntimeChildDefinition {
|
|||
|
||||
@Override
|
||||
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||
myRuntimeDef = new RuntimeResourceReferenceDefinition(getElementName(), myResourceTypes);
|
||||
myRuntimeDef = new RuntimeResourceReferenceDefinition(getElementName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.ResourceReference;
|
||||
import ca.uhn.fhir.model.api.UndeclaredExtension;
|
||||
|
||||
public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildDefinition {
|
||||
|
||||
|
||||
private Map<String, BaseRuntimeElementDefinition<?>> myAttributeNameToDefinition;
|
||||
private Map<Class<? extends IElement>,String> myDatatypeToAttributeName;
|
||||
private Map<Class<? extends IElement>,BaseRuntimeElementDefinition<?>> myDatatypeToDefinition;
|
||||
|
||||
public RuntimeChildUndeclaredExtensionDefinition(Map<String, BaseRuntimeElementDefinition<?>> theDatatypeAttributeNameToDefinition) {
|
||||
myAttributeNameToDefinition=theDatatypeAttributeNameToDefinition;
|
||||
|
||||
myDatatypeToAttributeName = new HashMap<Class<? extends IElement>, String>();
|
||||
myDatatypeToDefinition = new HashMap<Class<? extends IElement>, BaseRuntimeElementDefinition<?>>();
|
||||
|
||||
for (Entry<String, BaseRuntimeElementDefinition<?>> next : myAttributeNameToDefinition.entrySet()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends IDatatype> type = (Class<? extends IDatatype>) next.getValue().getImplementingClass();
|
||||
myDatatypeToAttributeName.put(type, next.getKey());
|
||||
myDatatypeToDefinition.put(type, next.getValue());
|
||||
}
|
||||
|
||||
// Resource Reference
|
||||
myDatatypeToAttributeName.put(ResourceReference.class, "valueReference");
|
||||
RuntimeResourceReferenceDefinition def = new RuntimeResourceReferenceDefinition("valueResource");
|
||||
myAttributeNameToDefinition.put("valueResource", def);
|
||||
myDatatypeToDefinition.put(ResourceReference.class, def);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BaseRuntimeElementDefinition<?> getChildByName(String theName) {
|
||||
return myAttributeNameToDefinition.get(theName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getValidChildNames() {
|
||||
return myAttributeNameToDefinition.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChildNameByDatatype(Class<? extends IElement> theDatatype) {
|
||||
return myDatatypeToAttributeName.get(theDatatype);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theType) {
|
||||
return myDatatypeToDefinition.get(theType);
|
||||
}
|
||||
|
||||
@Override
|
||||
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IAccessor getAccessor() {
|
||||
return new IAccessor() {
|
||||
@Override
|
||||
public List<? extends IElement> getValues(Object theTarget) {
|
||||
UndeclaredExtension target = (UndeclaredExtension)theTarget;
|
||||
if (target.getValue() != null) {
|
||||
return Collections.singletonList(target.getValue());
|
||||
}
|
||||
return target.getUndeclaredExtensions();
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IMutator getMutator() {
|
||||
return new IMutator() {
|
||||
@Override
|
||||
public void addValue(Object theTarget, IElement theValue) {
|
||||
UndeclaredExtension target = (UndeclaredExtension)theTarget;
|
||||
if (theValue instanceof IDatatype) {
|
||||
target.setValue((IDatatype) theTarget);
|
||||
}else {
|
||||
target.getUndeclaredExtensions().add((UndeclaredExtension) theValue);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
}
|
|
@ -2,13 +2,12 @@ package ca.uhn.fhir.context;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
|
||||
public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition<IPrimitiveDatatype>{
|
||||
public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition<IPrimitiveDatatype<?>>{
|
||||
|
||||
public RuntimePrimitiveDatatypeDefinition(String theName, Class<? extends IPrimitiveDatatype> theImplementingClass) {
|
||||
public RuntimePrimitiveDatatypeDefinition(String theName, Class<? extends IPrimitiveDatatype<?>> theImplementingClass) {
|
||||
super(theName, theImplementingClass);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
import java.util.Map;
|
||||
|
||||
public class RuntimePrimitiveDatatypeNarrativeDefinition extends RuntimePrimitiveDatatypeDefinition {
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.datatype.XhtmlDt;
|
||||
|
||||
public RuntimePrimitiveDatatypeNarrativeDefinition(String theName, Class<? extends IPrimitiveDatatype<?>> theImplementingClass) {
|
||||
public class RuntimePrimitiveDatatypeNarrativeDefinition extends BaseRuntimeElementDefinition<XhtmlDt> {
|
||||
|
||||
public RuntimePrimitiveDatatypeNarrativeDefinition(String theName, Class<XhtmlDt> theImplementingClass) {
|
||||
super(theName, theImplementingClass);
|
||||
}
|
||||
|
||||
|
@ -13,4 +16,9 @@ public class RuntimePrimitiveDatatypeNarrativeDefinition extends RuntimePrimitiv
|
|||
return ChildTypeEnum.PRIMITIVE_XHTML;
|
||||
}
|
||||
|
||||
@Override
|
||||
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceReference;
|
||||
|
||||
public class RuntimeResourceReferenceDefinition extends BaseRuntimeElementDefinition<ResourceReference> {
|
||||
|
||||
public RuntimeResourceReferenceDefinition(String theName, List<Class<? extends IResource>> theResourceTypes) {
|
||||
public RuntimeResourceReferenceDefinition(String theName) {
|
||||
super(theName, ResourceReference.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,20 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
public abstract class BaseElement implements IElement {
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class BaseElement implements IElement, ISupportsUndeclaredExtensions {
|
||||
|
||||
private List<UndeclaredExtension> myUndeclaredExtensions;
|
||||
|
||||
@Override
|
||||
public List<UndeclaredExtension> getUndeclaredExtensions() {
|
||||
if (myUndeclaredExtensions==null) {
|
||||
myUndeclaredExtensions=new ArrayList<UndeclaredExtension>();
|
||||
}
|
||||
return myUndeclaredExtensions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
public interface IExtension extends IElement {
|
||||
// nothing
|
||||
}
|
|
@ -6,7 +6,7 @@ public interface IPrimitiveDatatype<T> extends IDatatype {
|
|||
|
||||
void setValueAsString(String theValue) throws DataFormatException;
|
||||
|
||||
String getValueAsString();
|
||||
String getValueAsString() throws DataFormatException;
|
||||
|
||||
T getValue();
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISupportsUndeclaredExtensions {
|
||||
|
||||
/**
|
||||
* Returns a list containing all undeclared extensions
|
||||
*/
|
||||
List<UndeclaredExtension> getUndeclaredExtensions();
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
public class UndeclaredExtension extends BaseElement {
|
||||
|
||||
private String myUrl;
|
||||
private IElement myValue;
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
public IElement getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
public void setUrl(String theUrl) {
|
||||
myUrl = theUrl;
|
||||
}
|
||||
|
||||
public void setValue(IElement theValue) {
|
||||
myValue = theValue;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ca.uhn.fhir.model.api.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
|
||||
@Target(value= {ElementType.FIELD})
|
||||
public @interface Extension {
|
||||
|
||||
String url();
|
||||
|
||||
Class<? extends IDatatype> datatype() default NoDatatype.class;
|
||||
|
||||
public static class NoDatatype implements IDatatype
|
||||
{
|
||||
private NoDatatype() {
|
||||
// non-instantiable
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package ca.uhn.fhir.model.api.annotation;
|
||||
|
||||
public @interface ExtensionBlock {
|
||||
|
||||
String url();
|
||||
|
||||
}
|
|
@ -1,5 +1,15 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -243,4 +253,5 @@ P.O. Box number, delivery hints, and similar address information
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -17,7 +17,7 @@ public abstract class BaseDateTimeDt extends BasePrimitiveDatatype<Date> {
|
|||
private static final FastDateFormat ourYearMonthDayFormat = FastDateFormat.getInstance("yyyy-MM-dd");
|
||||
private static final FastDateFormat ourYearMonthFormat = FastDateFormat.getInstance("yyyy-MM");
|
||||
private static final FastDateFormat ourYearMonthDayTimeFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
private static final FastDateFormat ourYearMonthDayTimeZoneFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssX");
|
||||
private static final FastDateFormat ourYearMonthDayTimeZoneFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
|
||||
|
||||
private int myPrecision = Calendar.SECOND;
|
||||
private Date myValue;
|
||||
|
@ -114,7 +114,7 @@ public abstract class BaseDateTimeDt extends BasePrimitiveDatatype<Date> {
|
|||
setValue(ourYearMonthFormat.parse(theValue));
|
||||
setPrecision(Calendar.MONTH);
|
||||
clearTimeZone();
|
||||
} else if (theValue.length() == 9 && isPrecisionAllowed(Calendar.DAY_OF_MONTH)) {
|
||||
} else if (theValue.length() == 10 && isPrecisionAllowed(Calendar.DAY_OF_MONTH)) {
|
||||
setValue(ourYearMonthDayFormat.parse(theValue));
|
||||
setPrecision(Calendar.DAY_OF_MONTH);
|
||||
clearTimeZone();
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import ca.uhn.fhir.model.api.BasePrimitiveDatatype;
|
||||
import ca.uhn.fhir.model.api.ICodeEnum;
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
@DatatypeDef(name = "code")
|
||||
public class CodeDt extends BasePrimitiveDatatype<String> implements ICodedDatatype {
|
||||
public class CodeDt extends BasePrimitiveDatatype<String> implements ICodedDatatype, IPrimitiveDatatype<String> {
|
||||
|
||||
private String myValue;
|
||||
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -133,4 +143,5 @@ public class ContactDt extends BaseCompositeDatatype {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,15 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -214,4 +224,5 @@ public class HumanNameDt extends BaseCompositeDatatype {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -3,5 +3,5 @@ package ca.uhn.fhir.model.datatype;
|
|||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
|
||||
public interface ICodedDatatype extends IDatatype {
|
||||
|
||||
// nothing
|
||||
}
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -79,4 +89,5 @@ public class NarrativeDt extends BaseCompositeDatatype {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,15 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -160,4 +170,5 @@ public class QuantityDt extends BaseCompositeDatatype {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,32 +1,86 @@
|
|||
package ca.uhn.fhir.model.datatype;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.stream.FactoryConfigurationError;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLEventWriter;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
@DatatypeDef(name = "xhtml")
|
||||
public class XhtmlDt implements IPrimitiveDatatype<String> {
|
||||
public class XhtmlDt implements IPrimitiveDatatype<List<XMLEvent>> {
|
||||
|
||||
private String myValue;
|
||||
private List<XMLEvent> myValue;
|
||||
|
||||
@Override
|
||||
public void setValueAsString(String theValue) throws DataFormatException {
|
||||
myValue=theValue;
|
||||
if (theValue == null) {
|
||||
myValue = null;
|
||||
return;
|
||||
}
|
||||
String val = "<a>" + theValue + "</a>";
|
||||
try {
|
||||
ArrayList<XMLEvent> value = new ArrayList<XMLEvent>();
|
||||
XMLEventReader er = XMLInputFactory.newInstance().createXMLEventReader(new StringReader(val));
|
||||
boolean first = true;
|
||||
while (er.hasNext()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
XMLEvent next = er.nextEvent();
|
||||
if (er.hasNext()) {
|
||||
// don't add the last event
|
||||
value.add(next);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("String does not appear to be valid XML/XHTML", e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAsString() {
|
||||
public String getValueAsString() throws DataFormatException {
|
||||
if (myValue == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
StringWriter w = new StringWriter();
|
||||
XMLEventWriter ew = XMLOutputFactory.newInstance().createXMLEventWriter(w);
|
||||
for (XMLEvent next : myValue) {
|
||||
ew.add(next);
|
||||
}
|
||||
ew.close();
|
||||
return w.toString();
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("Problem with the contained XML events", e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XMLEvent> getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(String theValue) throws DataFormatException {
|
||||
myValue=theValue;
|
||||
public void setValue(List<XMLEvent> theValue) throws DataFormatException {
|
||||
myValue = theValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package ca.uhn.fhir.model.resource;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -1421,4 +1431,5 @@ public class Observation extends BaseResource {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,15 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package ca.uhn.fhir.model.resource;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -24,6 +34,10 @@ import ca.uhn.fhir.model.datatype.*;
|
|||
@ResourceDef(name="Patient")
|
||||
public class Patient extends BaseResource {
|
||||
|
||||
@Child()
|
||||
private Foo1 myFoo1;
|
||||
@Child()
|
||||
private Bar1 myBar1;
|
||||
@Child(name="identifier", order=0, min=0, max=Child.MAX_UNLIMITED)
|
||||
private List<IdentifierDt> myIdentifier;
|
||||
|
||||
|
@ -1950,4 +1964,35 @@ public class Patient extends BaseResource {
|
|||
}
|
||||
|
||||
|
||||
@ExtensionBlock(url="http://foo/1")
|
||||
public class Foo1 implements IExtension {
|
||||
|
||||
@Child(name="value", order=0)
|
||||
private StringDt myValue;
|
||||
|
||||
/**
|
||||
* Gets the value
|
||||
*/
|
||||
public StringDt getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value
|
||||
*/
|
||||
public void setValue(StringDt theValue) {
|
||||
myValue = theValue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ExtensionBlock(url="http://bar/1")
|
||||
public class Bar1 implements IExtension {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
|
@ -16,15 +13,20 @@ 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.RuntimePrimitiveDatatypeNarrativeDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceReferenceDefinition;
|
||||
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
|
||||
import ca.uhn.fhir.model.api.ICompositeDatatype;
|
||||
import ca.uhn.fhir.model.api.ICompositeElement;
|
||||
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.UndeclaredExtension;
|
||||
import ca.uhn.fhir.model.datatype.XhtmlDt;
|
||||
|
||||
class ParserState {
|
||||
|
||||
|
@ -51,6 +53,10 @@ class ParserState {
|
|||
myState.enteringNewElement(theElement, theName);
|
||||
}
|
||||
|
||||
public void enteringNewElementExtension(StartElement theElem, String theUrlAttr) {
|
||||
myState.enteringNewElementExtension(theElem, theUrlAttr);
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return myObject;
|
||||
}
|
||||
|
@ -59,6 +65,10 @@ class ParserState {
|
|||
return myObject != null;
|
||||
}
|
||||
|
||||
public void otherEvent(XMLEvent theEvent) throws DataFormatException {
|
||||
myState.otherEvent(theEvent);
|
||||
}
|
||||
|
||||
private void pop() {
|
||||
myState = myState.myStack;
|
||||
}
|
||||
|
@ -96,11 +106,25 @@ class ParserState {
|
|||
|
||||
public abstract void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException;
|
||||
|
||||
public void enteringNewElementExtension(@SuppressWarnings("unused") StartElement theElement, String theUrlAttr) {
|
||||
// TODO: handle predefined extensions
|
||||
|
||||
if (getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
|
||||
UndeclaredExtension newExtension = new UndeclaredExtension();
|
||||
newExtension.setUrl(theUrlAttr);
|
||||
((ISupportsUndeclaredExtensions) getCurrentElement()).getUndeclaredExtensions().add(newExtension);
|
||||
ExtensionState newState = new ExtensionState(newExtension);
|
||||
push(newState);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void otherEvent(XMLEvent theEvent) throws DataFormatException;
|
||||
|
||||
public void setStack(BaseState theState) {
|
||||
myStack = theState;
|
||||
}
|
||||
|
||||
public abstract void otherEvent(XMLEvent theEvent);
|
||||
protected abstract IElement getCurrentElement();
|
||||
|
||||
}
|
||||
|
||||
|
@ -165,18 +189,107 @@ class ParserState {
|
|||
push(newState);
|
||||
return;
|
||||
}
|
||||
case PRIMITIVE_XHTML: {
|
||||
RuntimePrimitiveDatatypeNarrativeDefinition xhtmlTarget = (RuntimePrimitiveDatatypeNarrativeDefinition) target;
|
||||
XhtmlDt newDt = xhtmlTarget.newInstance();
|
||||
child.getMutator().addValue(myInstance, newDt);
|
||||
XhtmlState state = new XhtmlState(newDt, theElement);
|
||||
push(state);
|
||||
return;
|
||||
}
|
||||
case UNDECL_EXT:
|
||||
case RESOURCE: {
|
||||
// Throw an exception because this shouldn't happen here
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_XHTML: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
throw new DataFormatException("Illegal resource position: " + target.getChildType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void otherEvent(XMLEvent theEvent) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ExtensionState extends BaseState {
|
||||
|
||||
private UndeclaredExtension myExtension;
|
||||
|
||||
public ExtensionState(UndeclaredExtension theExtension) {
|
||||
myExtension = theExtension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
|
||||
throw new DataFormatException("'value' attribute is invalid in 'extension' element");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement(EndElement theElem) throws DataFormatException {
|
||||
if (myExtension.getValue() != null && myExtension.getUndeclaredExtensions().size() > 0) {
|
||||
throw new DataFormatException("Extension must not have both a value and other contained extensions");
|
||||
}
|
||||
pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException {
|
||||
BaseRuntimeElementDefinition<?> target = myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildByName(theLocalPart);
|
||||
if (target == null) {
|
||||
throw new DataFormatException("Unknown extension element name: " + theLocalPart);
|
||||
}
|
||||
|
||||
switch (target.getChildType()) {
|
||||
case COMPOSITE_DATATYPE: {
|
||||
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
||||
ICompositeDatatype newChildInstance = (ICompositeDatatype) compositeTarget.newInstance();
|
||||
myExtension.setValue(newChildInstance);
|
||||
ContainerState newState = new ContainerState(compositeTarget, newChildInstance);
|
||||
push(newState);
|
||||
return;
|
||||
}
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
||||
IPrimitiveDatatype<?> newChildInstance = primitiveTarget.newInstance();
|
||||
myExtension.setValue(newChildInstance);
|
||||
PrimitiveState newState = new PrimitiveState(newChildInstance);
|
||||
push(newState);
|
||||
return;
|
||||
}
|
||||
case RESOURCE_REF: {
|
||||
RuntimeResourceReferenceDefinition resourceRefTarget = (RuntimeResourceReferenceDefinition) target;
|
||||
ResourceReference newChildInstance = new ResourceReference();
|
||||
myExtension.setValue(newChildInstance);
|
||||
ResourceReferenceState newState = new ResourceReferenceState(resourceRefTarget, newChildInstance);
|
||||
push(newState);
|
||||
return;
|
||||
}
|
||||
case PRIMITIVE_XHTML:
|
||||
case RESOURCE:
|
||||
case RESOURCE_BLOCK:
|
||||
case UNDECL_EXT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void otherEvent(XMLEvent theEvent) throws DataFormatException {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myExtension;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class PrimitiveState extends BaseState {
|
||||
|
@ -202,6 +315,16 @@ class ParserState {
|
|||
throw new Error("?? can this happen?"); // TODO: can this happen?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void otherEvent(XMLEvent theEvent) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ResourceReferenceState extends BaseState {
|
||||
|
@ -260,6 +383,16 @@ class ParserState {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void otherEvent(XMLEvent theEvent) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum ResourceReferenceSubState {
|
||||
|
@ -267,47 +400,47 @@ class ParserState {
|
|||
}
|
||||
|
||||
private class XhtmlState extends BaseState {
|
||||
private StringWriter myStringWriter;
|
||||
private XMLEventWriter myEventWriter;
|
||||
private XMLEventFactory myEventFactory;
|
||||
private int myDepth;
|
||||
private XhtmlDt myDt;
|
||||
private List<XMLEvent> myEvents = new ArrayList<XMLEvent>();
|
||||
|
||||
private XhtmlState() throws DataFormatException {
|
||||
try {
|
||||
XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
|
||||
myStringWriter = new StringWriter();
|
||||
myEventWriter = xmlFactory.createXMLEventWriter(myStringWriter);
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException(e);
|
||||
}
|
||||
private XhtmlState(XhtmlDt theXhtmlDt, StartElement theXhtmlStartElement) throws DataFormatException {
|
||||
myDepth = 1;
|
||||
myDt = theXhtmlDt;
|
||||
myEvents.add(theXhtmlStartElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeValue(Attribute theAttr, String theValue) throws DataFormatException {
|
||||
try {
|
||||
myEventWriter.add(theAttr);
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException(e);
|
||||
}
|
||||
myEvents.add(theAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement(EndElement theElement) throws DataFormatException {
|
||||
try {
|
||||
myEventWriter.add(theElement);
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException(e);
|
||||
myEvents.add(theElement);
|
||||
|
||||
myDepth--;
|
||||
if (myDepth == 0) {
|
||||
myDt.setValue(myEvents);
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(StartElement theElem, String theLocalPart) throws DataFormatException {
|
||||
// TODO Auto-generated method stub
|
||||
myDepth++;
|
||||
myEvents.add(theElem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void otherEvent(XMLEvent theEvent) throws DataFormatException {
|
||||
myEvents.add(theEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myDt;
|
||||
}
|
||||
}
|
||||
|
||||
public void otherEvent(XMLEvent theEvent) {
|
||||
myState.otherEvent(theEvent);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +1,28 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.FactoryConfigurationError;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.Comment;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.EntityReference;
|
||||
import javax.xml.stream.events.Namespace;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -24,14 +31,20 @@ import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
|||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.IExtension;
|
||||
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
|
||||
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.ResourceReference;
|
||||
import ca.uhn.fhir.model.api.UndeclaredExtension;
|
||||
import ca.uhn.fhir.model.datatype.XhtmlDt;
|
||||
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
|
||||
|
||||
public class XmlParser {
|
||||
private static final String XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
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);
|
||||
|
@ -45,13 +58,13 @@ public class XmlParser {
|
|||
myXmlOutputFactory = XMLOutputFactory.newInstance();
|
||||
}
|
||||
|
||||
public String encodeResourceToString(IResource theResource) {
|
||||
public String encodeResourceToString(IResource theResource) throws DataFormatException {
|
||||
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);
|
||||
|
@ -67,9 +80,10 @@ public class XmlParser {
|
|||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
private void encodeCompositeElementToStreamWriter(IElement theResource, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws XMLStreamException {
|
||||
private void encodeCompositeElementToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter,BaseRuntimeElementCompositeDefinition<?> resDef) throws XMLStreamException, DataFormatException {
|
||||
encodeExtensionsIfPresent(theEventWriter, theElement);
|
||||
for (BaseRuntimeChildDefinition nextChild : resDef.getChildren()) {
|
||||
List<IElement> values = nextChild.getAccessor().getValues(theResource);
|
||||
List<? extends IElement> values = nextChild.getAccessor().getValues(theElement);
|
||||
if (values == null || values.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -81,34 +95,146 @@ public class XmlParser {
|
|||
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();
|
||||
encodeChildElementToStreamWriter(theEventWriter, nextValue, childName, childDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeChildElementToStreamWriter(XMLStreamWriter theEventWriter, IElement nextValue, String childName, BaseRuntimeElementDefinition<?> childDef) throws XMLStreamException, DataFormatException {
|
||||
switch (childDef.getChildType()) {
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
IPrimitiveDatatype<?> pd = (IPrimitiveDatatype<?>) nextValue;
|
||||
theEventWriter.writeAttribute("value", pd.getValueAsString());
|
||||
encodeExtensionsIfPresent(theEventWriter, nextValue);
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
}
|
||||
case RESOURCE_BLOCK:
|
||||
case COMPOSITE_DATATYPE: {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
BaseRuntimeElementCompositeDefinition<?> childCompositeDef = (BaseRuntimeElementCompositeDefinition<?>) childDef;
|
||||
encodeCompositeElementToStreamWriter(nextValue, theEventWriter, childCompositeDef);
|
||||
encodeExtensionsIfPresent(theEventWriter, nextValue);
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
}
|
||||
case RESOURCE_REF: {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
ResourceReference ref = (ResourceReference) nextValue;
|
||||
encodeResourceReferenceToStreamWriter(theEventWriter, ref);
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
}
|
||||
case RESOURCE: {
|
||||
throw new IllegalStateException(); // should not happen
|
||||
}
|
||||
case PRIMITIVE_XHTML: {
|
||||
XhtmlDt dt = (XhtmlDt) nextValue;
|
||||
encodeXhtml(dt, theEventWriter);
|
||||
break;
|
||||
}
|
||||
case UNDECL_EXT: {
|
||||
throw new IllegalStateException("should not happen");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeExtensionsIfPresent(XMLStreamWriter theWriter, IElement theResource) throws XMLStreamException, DataFormatException {
|
||||
if (theResource instanceof ISupportsUndeclaredExtensions) {
|
||||
for (UndeclaredExtension next : ((ISupportsUndeclaredExtensions) theResource).getUndeclaredExtensions()) {
|
||||
theWriter.writeStartElement("extension");
|
||||
theWriter.writeAttribute("url", next.getUrl());
|
||||
|
||||
if (next.getValue() != null) {
|
||||
IElement nextValue = next.getValue();
|
||||
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
|
||||
String childName = extDef.getChildNameByDatatype(nextValue.getClass());
|
||||
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass());
|
||||
encodeChildElementToStreamWriter(theWriter, nextValue, childName, childDef);
|
||||
}
|
||||
|
||||
// child extensions
|
||||
encodeExtensionsIfPresent(theWriter, next);
|
||||
|
||||
theWriter.writeEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeXhtml(XhtmlDt theDt, XMLStreamWriter theEventWriter) throws XMLStreamException {
|
||||
if (theDt == null || theDt.getValue() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean firstEvent = true;
|
||||
for (XMLEvent event : theDt.getValue()) {
|
||||
switch (event.getEventType()) {
|
||||
case XMLStreamConstants.ATTRIBUTE:
|
||||
Attribute attr = (Attribute) event;
|
||||
if (isBlank(attr.getName().getPrefix())) {
|
||||
if (isBlank(attr.getName().getNamespaceURI())) {
|
||||
theEventWriter.writeAttribute(attr.getName().getLocalPart(), attr.getValue());
|
||||
} else {
|
||||
theEventWriter.writeAttribute(attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue());
|
||||
}
|
||||
} else {
|
||||
theEventWriter.writeAttribute(attr.getName().getPrefix(), attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue());
|
||||
}
|
||||
|
||||
break;
|
||||
case XMLStreamConstants.CDATA:
|
||||
theEventWriter.writeCData(((Characters) event).getData());
|
||||
break;
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
case XMLStreamConstants.SPACE:
|
||||
theEventWriter.writeCharacters(((Characters) event).getData());
|
||||
break;
|
||||
case XMLStreamConstants.COMMENT:
|
||||
theEventWriter.writeComment(((Comment) event).getText());
|
||||
break;
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
case XMLStreamConstants.ENTITY_REFERENCE:
|
||||
EntityReference er = (EntityReference) event;
|
||||
theEventWriter.writeEntityRef(er.getName());
|
||||
break;
|
||||
case XMLStreamConstants.NAMESPACE:
|
||||
Namespace ns = (Namespace) event;
|
||||
theEventWriter.writeNamespace(ns.getPrefix(), ns.getNamespaceURI());
|
||||
break;
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
StartElement se = event.asStartElement();
|
||||
if (firstEvent) {
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
theEventWriter.writeNamespace(se.getName().getPrefix(), se.getName().getNamespaceURI());
|
||||
} else {
|
||||
if (isBlank(se.getName().getPrefix())) {
|
||||
if (isBlank(se.getName().getNamespaceURI())) {
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
} else {
|
||||
theEventWriter.writeStartElement(se.getName().getNamespaceURI(), se.getName().getLocalPart());
|
||||
}
|
||||
} else {
|
||||
theEventWriter.writeStartElement(se.getName().getPrefix(), se.getName().getLocalPart(), se.getName().getNamespaceURI());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XMLStreamConstants.DTD:
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
case XMLStreamConstants.ENTITY_DECLARATION:
|
||||
case XMLStreamConstants.NOTATION_DECLARATION:
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION:
|
||||
case XMLStreamConstants.START_DOCUMENT:
|
||||
break;
|
||||
}
|
||||
|
||||
firstEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, ResourceReference theRef) throws XMLStreamException {
|
||||
if (StringUtils.isNotBlank(theRef.getDisplay())) {
|
||||
theEventWriter.writeStartElement("display");
|
||||
|
@ -138,21 +264,29 @@ public class XmlParser {
|
|||
XMLEvent nextEvent = streamReader.nextEvent();
|
||||
if (nextEvent.isStartElement()) {
|
||||
StartElement elem = nextEvent.asStartElement();
|
||||
if (!FHIR_NS.equals(elem.getName().getNamespaceURI())) {
|
||||
|
||||
String namespaceURI = elem.getName().getNamespaceURI();
|
||||
if (!FHIR_NS.equals(namespaceURI) && !XHTML_NS.equals(namespaceURI)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parserState == null) {
|
||||
parserState = ParserState.getResourceInstance(myContext, elem.getName().getLocalPart());
|
||||
} else if ("extension".equals(elem.getName().getLocalPart())) {
|
||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||
if (urlAttr==null||isBlank(urlAttr.getValue())) {
|
||||
throw new DataFormatException("Extension element has no 'url' attribute");
|
||||
}
|
||||
parserState.enteringNewElementExtension(elem, urlAttr.getValue());
|
||||
} else {
|
||||
parserState.enteringNewElement(elem.getName().getLocalPart());
|
||||
parserState.enteringNewElement(elem, 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());
|
||||
parserState.attributeValue(next, next.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,12 +301,14 @@ public class XmlParser {
|
|||
if (parserState == null) {
|
||||
throw new DataFormatException("Detected attribute before element");
|
||||
}
|
||||
parserState.attributeValue(elem.getValue());
|
||||
parserState.attributeValue(elem, elem.getValue());
|
||||
} else if (nextEvent.isEndElement()) {
|
||||
EndElement elem = nextEvent.asEndElement();
|
||||
if (!FHIR_NS.equals(elem.getName().getNamespaceURI())) {
|
||||
String namespaceURI = elem.getName().getNamespaceURI();
|
||||
if (!FHIR_NS.equals(namespaceURI) && !XHTML_NS.equals(namespaceURI)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parserState == null) {
|
||||
throw new DataFormatException("Detected unexpected end-element");
|
||||
}
|
||||
|
@ -181,7 +317,9 @@ public class XmlParser {
|
|||
return (IResource) parserState.getObject();
|
||||
}
|
||||
} else {
|
||||
parserState.otherEvent(nextEvent);
|
||||
if (parserState != null) {
|
||||
parserState.otherEvent(nextEvent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.junit.Test;
|
|||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.datatype.DateDt;
|
||||
import ca.uhn.fhir.model.resource.Observation;
|
||||
|
||||
public class XmlParserTest {
|
||||
|
|
|
@ -1,39 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
This example is taken from the v3 data types (SLIST)
|
||||
-->
|
||||
|
||||
<!-- This example is taken from the v3 data types (SLIST) -->
|
||||
|
||||
<Observation xmlns="http://hl7.org/fhir" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://hl7.org/fhir ..\..\schema\observation.xsd">
|
||||
<text>
|
||||
<status value="generated"/>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">Sept 17, 2012: Systolic Blood pressure 107 mmHg (normal)</div>
|
||||
</text>
|
||||
<name>
|
||||
<!-- Actually, this is not a vull EEG. A todo is to turn it into one -->
|
||||
<coding>
|
||||
<system value="http://loinc.org"/>
|
||||
<code value="11523-8"/>
|
||||
<display value="EEG study"/>
|
||||
</coding>
|
||||
</name>
|
||||
<valueSampledData>
|
||||
<origin>
|
||||
<value value="0"/>
|
||||
<units value="μV"/>
|
||||
<system value="http://unitsofmeasure.org"/>
|
||||
<code value="uV"/>
|
||||
</origin>
|
||||
<period value="100"/>
|
||||
<factor value="2.5"/>
|
||||
<dimensions value="1"/>
|
||||
<data value="-4 -13 -18 -18 -18 -17 -16 -16 -16 -16 -16 -17 -18 -18 -1 -17 -16 -16 -16 -15 -13 -11 -10 -10 -9 -6 -4 -5 -5 -3 -2 -2 -1 1 2 7 8 9 10 11 12 13 15 17 19 21 23 25 27 29 30 30 31 34 37 40 43 45 4 46 46 46 46 47 49 51 53 55 57 59 60 59 58 58 58 57 56 56 56 57 57 5 53 50 47 45 74 51 38 33 31 2 25 21 16 14 15 13 9 7 4 1 -1 -3 -4 -6 -10 -12 -13 -12 -12 -17 -18 -18 -18 -19 -20 -21 -20 -20 -20 -20 -2 2 1 0 0 0 1 2 2 1 1 1 0 -1 0 1 1 1 1 2 E"/>
|
||||
</valueSampledData>
|
||||
|
||||
<status value="final"/>
|
||||
<reliability value="ok"/>
|
||||
<extension url="http://acme.org/fhir/Profile/main#trial-status">
|
||||
<extension url="http://acme.org/fhir/Profile/main#trial-status-code">
|
||||
<valueCode value="unsure" />
|
||||
</extension>
|
||||
<extension url="http://acme.org/fhir/Profile/main#trial-status-date">
|
||||
<valueDate value="2009-03-14" />
|
||||
</extension>
|
||||
<extension url="http://acme.org/fhir/Profile/main#trial-status-who">
|
||||
<valueResource>
|
||||
<reference value="Practitioner/example" />
|
||||
</valueResource>
|
||||
</extension>
|
||||
</extension>
|
||||
<text>
|
||||
<status value="generated" />
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">Sept 17, 2012: Systolic Blood pressure 107 mmHg (normal)</div>
|
||||
</text>
|
||||
<name>
|
||||
<!-- Actually, this is not a vull EEG. A todo is to turn it into one -->
|
||||
<coding>
|
||||
<system value="http://loinc.org" />
|
||||
<code value="11523-8" />
|
||||
<display value="EEG study" />
|
||||
</coding>
|
||||
</name>
|
||||
<valueSampledData>
|
||||
<origin>
|
||||
<value value="0" />
|
||||
<units value="μV" />
|
||||
<system value="http://unitsofmeasure.org" />
|
||||
<code value="uV" />
|
||||
</origin>
|
||||
<period value="100" />
|
||||
<factor value="2.5" />
|
||||
<dimensions value="1" />
|
||||
<data
|
||||
value="-4 -13 -18 -18 -18 -17 -16 -16 -16 -16 -16 -17 -18 -18 -1 -17 -16 -16 -16 -15 -13 -11 -10 -10 -9 -6 -4 -5 -5 -3 -2 -2 -1 1 2 7 8 9 10 11 12 13 15 17 19 21 23 25 27 29 30 30 31 34 37 40 43 45 4 46 46 46 46 47 49 51 53 55 57 59 60 59 58 58 58 57 56 56 56 57 57 5 53 50 47 45 74 51 38 33 31 2 25 21 16 14 15 13 9 7 4 1 -1 -3 -4 -6 -10 -12 -13 -12 -12 -17 -18 -18 -18 -19 -20 -21 -20 -20 -20 -20 -2 2 1 0 0 0 1 2 2 1 1 1 0 -1 0 1 1 1 1 2 E" />
|
||||
</valueSampledData>
|
||||
|
||||
<status value="final" />
|
||||
<reliability value="ok" />
|
||||
|
||||
|
||||
<subject>
|
||||
<reference value="Patient/example"/>
|
||||
</subject>
|
||||
<subject>
|
||||
<reference value="Patient/example" />
|
||||
</subject>
|
||||
</Observation>
|
|
@ -8,9 +8,11 @@ import java.io.FileWriter;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
import org.apache.velocity.app.VelocityEngine;
|
||||
|
@ -19,30 +21,29 @@ import org.w3c.dom.Element;
|
|||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import ch.qos.logback.core.db.dialect.MySQLDialect;
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.ResourceReference;
|
||||
import ca.uhn.fhir.model.datatype.CodeDt;
|
||||
import ca.uhn.fhir.model.datatype.CodeableConceptDt;
|
||||
import ca.uhn.fhir.starter.model.BaseElement;
|
||||
import ca.uhn.fhir.starter.model.Child;
|
||||
import ca.uhn.fhir.starter.model.Extension;
|
||||
import ca.uhn.fhir.starter.model.Resource;
|
||||
import ca.uhn.fhir.starter.model.ResourceBlock;
|
||||
import ca.uhn.fhir.starter.util.XMLUtils;
|
||||
|
||||
public abstract class BaseParser {
|
||||
|
||||
private String myDirectory;
|
||||
private String myOutputFile;
|
||||
private int myColName;
|
||||
private int myColCard;
|
||||
private int myColType;
|
||||
private int myColBinding;
|
||||
private int myColShortName;
|
||||
private int myColDefinition;
|
||||
private int myColV2Mapping;
|
||||
private int myColRequirements;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
|
||||
private int myColBinding;
|
||||
private int myColCard;
|
||||
private int myColDefinition;
|
||||
private int myColName;
|
||||
private int myColRequirements;
|
||||
private int myColShortName;
|
||||
private int myColType;
|
||||
private int myColV2Mapping;
|
||||
private String myDirectory;
|
||||
private ArrayList<Extension> myExtensions;
|
||||
private String myOutputFile;
|
||||
|
||||
public void parse() throws Exception {
|
||||
File baseDir = new File(myDirectory);
|
||||
|
@ -145,66 +146,14 @@ public abstract class BaseParser {
|
|||
myDirectory = theDirectory;
|
||||
}
|
||||
|
||||
public void setExtensions(ArrayList<Extension> theExts) {
|
||||
myExtensions = theExts;
|
||||
}
|
||||
|
||||
public void setOutputFile(String theOutputFile) {
|
||||
myOutputFile = theOutputFile;
|
||||
}
|
||||
|
||||
static String cellValue(Node theRowXml, int theCellIndex) {
|
||||
NodeList cells = ((Element) theRowXml).getElementsByTagName("Cell");
|
||||
|
||||
for (int i = 0, currentCell = 0; i < cells.getLength(); i++) {
|
||||
Element nextCell = (Element) cells.item(i);
|
||||
String indexVal = nextCell.getAttributeNS("urn:schemas-microsoft-com:office:spreadsheet", "Index");
|
||||
if (StringUtils.isNotBlank(indexVal)) {
|
||||
// 1-indexed for some reason...
|
||||
currentCell = Integer.parseInt(indexVal) - 1;
|
||||
}
|
||||
|
||||
if (currentCell == theCellIndex) {
|
||||
NodeList dataElems = nextCell.getElementsByTagName("Data");
|
||||
Element dataElem = (Element) dataElems.item(0);
|
||||
if (dataElem == null) {
|
||||
return null;
|
||||
}
|
||||
String retVal = dataElem.getTextContent();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
currentCell++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void write(Resource theResource) throws IOException {
|
||||
File f = new File(myOutputFile);
|
||||
FileWriter w = new FileWriter(f, false);
|
||||
|
||||
ourLog.info("Writing file: {}", f.getAbsolutePath());
|
||||
|
||||
VelocityContext ctx = new VelocityContext();
|
||||
ctx.put("className", theResource.getName());
|
||||
ctx.put("shortName", defaultString(theResource.getShortName()));
|
||||
ctx.put("definition", defaultString(theResource.getDefinition()));
|
||||
ctx.put("requirements", defaultString(theResource.getRequirement()));
|
||||
ctx.put("children", theResource.getChildren());
|
||||
ctx.put("resourceBlockChildren", theResource.getResourceBlockChildren());
|
||||
|
||||
VelocityEngine v = new VelocityEngine();
|
||||
v.setProperty("resource.loader", "cp");
|
||||
v.setProperty("cp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||
|
||||
InputStream templateIs = ResourceParser.class.getResourceAsStream(getTemplate());
|
||||
InputStreamReader templateReader = new InputStreamReader(templateIs);
|
||||
v.evaluate(ctx, w, "", templateReader);
|
||||
|
||||
w.close();
|
||||
}
|
||||
|
||||
protected abstract String getFilename();
|
||||
|
||||
protected abstract String getTemplate();
|
||||
|
||||
private void parseFirstRow(Element theDefRow) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
String nextName = cellValue(theDefRow, i);
|
||||
|
@ -232,6 +181,36 @@ public abstract class BaseParser {
|
|||
}
|
||||
}
|
||||
|
||||
private void write(Resource theResource) throws IOException {
|
||||
File f = new File(myOutputFile);
|
||||
FileWriter w = new FileWriter(f, false);
|
||||
|
||||
ourLog.info("Writing file: {}", f.getAbsolutePath());
|
||||
|
||||
VelocityContext ctx = new VelocityContext();
|
||||
ctx.put("className", theResource.getName());
|
||||
ctx.put("shortName", defaultString(theResource.getShortName()));
|
||||
ctx.put("definition", defaultString(theResource.getDefinition()));
|
||||
ctx.put("requirements", defaultString(theResource.getRequirement()));
|
||||
ctx.put("children", theResource.getChildren());
|
||||
ctx.put("resourceBlockChildren", theResource.getResourceBlockChildren());
|
||||
ctx.put("childExtensionTypes", ObjectUtils.defaultIfNull(myExtensions, new ArrayList<Extension>()));
|
||||
|
||||
VelocityEngine v = new VelocityEngine();
|
||||
v.setProperty("resource.loader", "cp");
|
||||
v.setProperty("cp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||
|
||||
InputStream templateIs = ResourceParser.class.getResourceAsStream(getTemplate());
|
||||
InputStreamReader templateReader = new InputStreamReader(templateIs);
|
||||
v.evaluate(ctx, w, "", templateReader);
|
||||
|
||||
w.close();
|
||||
}
|
||||
|
||||
protected abstract String getFilename();
|
||||
|
||||
protected abstract String getTemplate();
|
||||
|
||||
protected void parseBasicElements(Element theRowXml, BaseElement theTarget) {
|
||||
String name = cellValue(theRowXml, myColName);
|
||||
theTarget.setName(name);
|
||||
|
@ -263,4 +242,31 @@ public abstract class BaseParser {
|
|||
theTarget.setV2Mapping(cellValue(theRowXml, myColV2Mapping));
|
||||
}
|
||||
|
||||
static String cellValue(Node theRowXml, int theCellIndex) {
|
||||
NodeList cells = ((Element) theRowXml).getElementsByTagName("Cell");
|
||||
|
||||
for (int i = 0, currentCell = 0; i < cells.getLength(); i++) {
|
||||
Element nextCell = (Element) cells.item(i);
|
||||
String indexVal = nextCell.getAttributeNS("urn:schemas-microsoft-com:office:spreadsheet", "Index");
|
||||
if (StringUtils.isNotBlank(indexVal)) {
|
||||
// 1-indexed for some reason...
|
||||
currentCell = Integer.parseInt(indexVal) - 1;
|
||||
}
|
||||
|
||||
if (currentCell == theCellIndex) {
|
||||
NodeList dataElems = nextCell.getElementsByTagName("Data");
|
||||
Element dataElem = (Element) dataElems.item(0);
|
||||
if (dataElem == null) {
|
||||
return null;
|
||||
}
|
||||
String retVal = dataElem.getTextContent();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
currentCell++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package ca.uhn.fhir.starter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ca.uhn.fhir.model.datatype.DateDt;
|
||||
import ca.uhn.fhir.model.datatype.StringDt;
|
||||
import ca.uhn.fhir.starter.model.Extension;
|
||||
|
||||
public class ResourceParser extends BaseParser {
|
||||
private String myResourceName;
|
||||
|
@ -13,50 +18,59 @@ public class ResourceParser extends BaseParser {
|
|||
return myResourceName + "-spreadsheet.xml";
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void parseBasicElements(Element theRowXml, BaseElement
|
||||
// theTarget) {
|
||||
// String name = cellValue(theRowXml, 0);
|
||||
// theTarget.setName(name);
|
||||
//
|
||||
// int lastDot = name.lastIndexOf('.');
|
||||
// if (lastDot == -1) {
|
||||
// theTarget.setElementName(name);
|
||||
// } else {
|
||||
// String elementName = name.substring(lastDot + 1);
|
||||
// String elementParentName = name.substring(0, lastDot);
|
||||
// theTarget.setElementName(elementName);
|
||||
// theTarget.setElementParentName(elementParentName);
|
||||
// }
|
||||
//
|
||||
// String cardValue = cellValue(theRowXml, 1);
|
||||
// if (cardValue != null && cardValue.contains("..")) {
|
||||
// String[] split = cardValue.split("\\.\\.");
|
||||
// theTarget.setCardMin(split[0]);
|
||||
// theTarget.setCardMax(split[1]);
|
||||
// }
|
||||
//
|
||||
// String type = cellValue(theRowXml, 5);
|
||||
// theTarget.setTypeFromString(type);
|
||||
//
|
||||
// theTarget.setBinding(cellValue(theRowXml, 6));
|
||||
// theTarget.setShortName(cellValue(theRowXml, 7));
|
||||
// theTarget.setDefinition(cellValue(theRowXml, 8));
|
||||
// theTarget.setRequirement(cellValue(theRowXml, 9));
|
||||
// theTarget.setV2Mapping(cellValue(theRowXml, 14));
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected String getTemplate() {
|
||||
return "/resource.vm";
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void parseBasicElements(Element theRowXml, BaseElement theTarget) {
|
||||
// String name = cellValue(theRowXml, 0);
|
||||
// theTarget.setName(name);
|
||||
//
|
||||
// int lastDot = name.lastIndexOf('.');
|
||||
// if (lastDot == -1) {
|
||||
// theTarget.setElementName(name);
|
||||
// } else {
|
||||
// String elementName = name.substring(lastDot + 1);
|
||||
// String elementParentName = name.substring(0, lastDot);
|
||||
// theTarget.setElementName(elementName);
|
||||
// theTarget.setElementParentName(elementParentName);
|
||||
// }
|
||||
//
|
||||
// String cardValue = cellValue(theRowXml, 1);
|
||||
// if (cardValue != null && cardValue.contains("..")) {
|
||||
// String[] split = cardValue.split("\\.\\.");
|
||||
// theTarget.setCardMin(split[0]);
|
||||
// theTarget.setCardMax(split[1]);
|
||||
// }
|
||||
//
|
||||
// String type = cellValue(theRowXml, 5);
|
||||
// theTarget.setTypeFromString(type);
|
||||
//
|
||||
// theTarget.setBinding(cellValue(theRowXml, 6));
|
||||
// theTarget.setShortName(cellValue(theRowXml, 7));
|
||||
// theTarget.setDefinition(cellValue(theRowXml, 8));
|
||||
// theTarget.setRequirement(cellValue(theRowXml, 9));
|
||||
// theTarget.setV2Mapping(cellValue(theRowXml, 14));
|
||||
// }
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ResourceParser p = new ResourceParser();
|
||||
p.setDirectory("src/test/resources/res");
|
||||
p.setResourceName("patient");
|
||||
p.setOutputFile("../hapi-fhir-base/src/main/java/ca/uhn/fhir/model/resource/Patient.java");
|
||||
ArrayList<Extension> exts = new ArrayList<Extension>();
|
||||
Extension ext1 = new Extension("foo1", "http://foo/1", StringDt.class);
|
||||
exts.add(ext1);
|
||||
Extension ext2 = new Extension("bar1", "http://bar/1", new Extension("bar11", "http://bar/1/1", DateDt.class), new Extension("bar12", "http://bar/1/2", DateDt.class));
|
||||
exts.add(ext2);
|
||||
p.setExtensions(exts);
|
||||
p.parse();
|
||||
|
||||
p = new ResourceParser();
|
||||
p.setDirectory("src/test/resources/res");
|
||||
p.setResourceName("observation");
|
||||
p.setOutputFile("../hapi-fhir-base/src/main/java/ca/uhn/fhir/model/resource/Observation.java");
|
||||
p.parse();
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package ca.uhn.fhir.starter.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
|
||||
public class Extension {
|
||||
|
||||
private List<Extension> myChildExtensions;
|
||||
private Class<? extends IDatatype> myDatatype;
|
||||
private String myName;
|
||||
private String myUrl;
|
||||
|
||||
public Extension() {
|
||||
super();
|
||||
}
|
||||
|
||||
public boolean isHasDatatype() {
|
||||
return myDatatype != null;
|
||||
}
|
||||
|
||||
public String getDatatypeSimpleName() {
|
||||
return myDatatype.getSimpleName();
|
||||
}
|
||||
|
||||
public String getNameType() {
|
||||
return getName().substring(0, 1).toUpperCase()+getName().substring(1);
|
||||
}
|
||||
|
||||
public Extension(String theName, String theUrl, Class<? extends IDatatype> theDatatype) {
|
||||
setName(theName);
|
||||
setUrl(theUrl);
|
||||
setDatatype(theDatatype);
|
||||
}
|
||||
|
||||
public Extension(String theName, String theUrl, Extension... theChildExtensions) {
|
||||
setName(theName);
|
||||
setUrl(theUrl);
|
||||
if (theChildExtensions != null) {
|
||||
setChildExtensions(Arrays.asList(theChildExtensions));
|
||||
}
|
||||
}
|
||||
|
||||
public List<Extension> getChildExtensions() {
|
||||
return myChildExtensions;
|
||||
}
|
||||
|
||||
public Class<? extends IDatatype> getDatatype() {
|
||||
return myDatatype;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
public void setChildExtensions(List<Extension> theChildExtensions) {
|
||||
if (theChildExtensions != null && theChildExtensions.size() > 0 && myDatatype != null) {
|
||||
throw new IllegalArgumentException("Extension may not have a datatype AND child extensions");
|
||||
}
|
||||
myChildExtensions = theChildExtensions;
|
||||
}
|
||||
|
||||
public void setDatatype(Class<? extends IDatatype> theDatatype) {
|
||||
if (myChildExtensions != null && myChildExtensions.size() > 0 && theDatatype != null) {
|
||||
throw new IllegalArgumentException("Extension may not have a datatype AND child extensions");
|
||||
}
|
||||
myDatatype = theDatatype;
|
||||
}
|
||||
|
||||
public void setName(String theName) {
|
||||
// TODO: validate that this is a valid name (no punctuation, spaces,
|
||||
// etc.)
|
||||
myName = theName;
|
||||
}
|
||||
|
||||
public void setUrl(String theUrl) {
|
||||
myUrl = theUrl;
|
||||
}
|
||||
}
|
|
@ -24,7 +24,10 @@ import ca.uhn.fhir.model.datatype.*;
|
|||
@DatatypeDef(name="${className}")
|
||||
public class ${className}Dt extends BaseCompositeDatatype {
|
||||
|
||||
#childExtensionFields( $childExtensionTypes )
|
||||
#childVars( $children )
|
||||
#childAccessors( $children )
|
||||
|
||||
#childExtensionTypes( $childExtensionTypes )
|
||||
|
||||
}
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.model.datatype.*;
|
|||
@ResourceDef(name="${className}")
|
||||
public class ${className} extends BaseResource {
|
||||
|
||||
#childExtensionFields( $childExtensionTypes )
|
||||
#childVars( $children )
|
||||
#childAccessors( $children )
|
||||
|
||||
|
@ -44,4 +45,6 @@ public class ${className} extends BaseResource {
|
|||
|
||||
#end
|
||||
|
||||
#childExtensionTypes( $childExtensionTypes )
|
||||
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
##################################################################
|
||||
## childVars
|
||||
##################################################################
|
||||
|
||||
#macro ( childVars $childElements )
|
||||
#foreach ( $child in $children )
|
||||
#if ($child.resourceRef)
|
||||
|
@ -21,6 +25,11 @@
|
|||
#end
|
||||
#end
|
||||
|
||||
|
||||
##################################################################
|
||||
## childAccessors
|
||||
##################################################################
|
||||
|
||||
#macro ( childAccessors $childElements )
|
||||
#foreach ( $child in $children )
|
||||
/**
|
||||
|
@ -49,3 +58,53 @@
|
|||
|
||||
#end
|
||||
#end
|
||||
|
||||
##################################################################
|
||||
## childExtensionFields
|
||||
##################################################################
|
||||
|
||||
#macro ( childExtensionFields $childExtensionTypes )
|
||||
#foreach ( $extensionType in $childExtensionTypes )
|
||||
@Child()
|
||||
private ${extensionType.nameType} my${extensionType.nameType};
|
||||
|
||||
#end
|
||||
#end
|
||||
|
||||
|
||||
##################################################################
|
||||
## childExtensionTypes
|
||||
##################################################################
|
||||
|
||||
#macro ( childExtensionTypes $childExtensionTypes )
|
||||
#foreach ( $extensionType in $childExtensionTypes )
|
||||
@ExtensionBlock(url="${extensionType.url}")
|
||||
public class ${extensionType.nameType} implements IExtension {
|
||||
|
||||
#if(${extensionType.hasDatatype})
|
||||
@Child(name="value", order=0)
|
||||
private ${extensionType.datatypeSimpleName} myValue;
|
||||
|
||||
/**
|
||||
* Gets the value
|
||||
*/
|
||||
public ${extensionType.datatypeSimpleName} getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value
|
||||
*/
|
||||
public void setValue(${extensionType.datatypeSimpleName} theValue) {
|
||||
myValue = theValue;
|
||||
}
|
||||
#else
|
||||
#end
|
||||
|
||||
|
||||
}
|
||||
|
||||
#end
|
||||
#end
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue