diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java index a90cb086b7d..827156ac2ac 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java @@ -183,7 +183,7 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil } } - private final class FieldPlainMutator implements IMutator { + protected final class FieldPlainMutator implements IMutator { @Override public void addValue(Object theTarget, IBase theValue) { try { @@ -214,7 +214,7 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil } } - private final class FieldListMutator implements IMutator { + protected final class FieldListMutator implements IMutator { @Override public void addValue(Object theTarget, IBase theValue) { try { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java index ba87643ca92..3be24b9f47a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeElementDefinition.java @@ -158,7 +158,26 @@ public abstract class BaseRuntimeElementDefinition { public abstract ChildTypeEnum getChildType(); public enum ChildTypeEnum { - COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK, PRIMITIVE_XHTML, UNDECL_EXT, EXTENSION_DECLARED, CONTAINED_RESOURCES + COMPOSITE_DATATYPE, PRIMITIVE_DATATYPE, RESOURCE, RESOURCE_REF, RESOURCE_BLOCK, + /** + * HAPI style + */ + PRIMITIVE_XHTML, + UNDECL_EXT, EXTENSION_DECLARED, + /** + * HAPI structure style + */ + CONTAINED_RESOURCES, + ID_DATATYPE, + /** + * HL7.org structure style + */ + CONTAINED_RESOURCE_LIST, + + /** + * HL7.org style + */ + PRIMITIVE_XHTML_HL7ORG } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java index a0a783f1bf3..4334f344a24 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java @@ -20,7 +20,7 @@ package ca.uhn.fhir.context; * #L% */ -import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.io.IOException; import java.io.InputStream; @@ -56,9 +56,11 @@ import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBackboneElement; import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseEnumFactory; +import org.hl7.fhir.instance.model.api.IBaseEnumeration; import org.hl7.fhir.instance.model.api.IBaseExtension; +import org.hl7.fhir.instance.model.api.IBaseXhtml; import org.hl7.fhir.instance.model.api.IDatatypeElement; -import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.INarrative; import org.hl7.fhir.instance.model.api.IReference; @@ -225,6 +227,7 @@ class ModelScanner { * all of the annotation processing code this method just creates an interface Proxy to simulate the HAPI * annotations if the HL7.org ones are found instead. */ + @SuppressWarnings("unchecked") private T pullAnnotation(AnnotatedElement theTarget, Class theAnnotationType) { T retVal = theTarget.getAnnotation(theAnnotationType); @@ -493,20 +496,20 @@ class ModelScanner { Class nextElementType = determineElementType(next); - if (IAnyResource.class.isAssignableFrom(nextElementType) || IResource.class.equals(nextElementType)) { - /* - * Child is a resource as a direct child, as in Bundle.entry.resource - */ - RuntimeChildDirectResource def = new RuntimeChildDirectResource(next, childAnnotation, descriptionAnnotation, elementName); - orderMap.put(order, def); - - } else if (BaseContainedDt.class.isAssignableFrom(nextElementType) || (childAnnotation.name().equals("contained") && IDomainResource.class.isAssignableFrom(theClass))) { + if (BaseContainedDt.class.isAssignableFrom(nextElementType) || (childAnnotation.name().equals("contained") && IBaseResource.class.isAssignableFrom(nextElementType))) { /* * Child is contained resources */ RuntimeChildContainedResources def = new RuntimeChildContainedResources(next, childAnnotation, descriptionAnnotation, elementName); orderMap.put(order, def); + } else if (IAnyResource.class.isAssignableFrom(nextElementType) || IResource.class.equals(nextElementType)) { + /* + * Child is a resource as a direct child, as in Bundle.entry.resource + */ + RuntimeChildDirectResource def = new RuntimeChildDirectResource(next, childAnnotation, descriptionAnnotation, elementName); + orderMap.put(order, def); + } else if (choiceTypes.size() > 1 && !BaseResourceReferenceDt.class.isAssignableFrom(nextElementType) && !IReference.class.isAssignableFrom(nextElementType)) { /* * Child is a choice element @@ -538,8 +541,8 @@ class ModelScanner { RuntimeChildDeclaredExtensionDefinition def = new RuntimeChildDeclaredExtensionDefinition(next, childAnnotation, descriptionAnnotation, extensionAttr, elementName, extensionAttr.url(), et, binder); orderMap.put(order, def); - if (IElement.class.isAssignableFrom(nextElementType)) { - addScanAlso((Class) nextElementType); + if (IBase.class.isAssignableFrom(nextElementType)) { + addScanAlso((Class) nextElementType); } } else if (BaseResourceReferenceDt.class.isAssignableFrom(nextElementType) || IReference.class.isAssignableFrom(nextElementType)) { /* @@ -582,17 +585,25 @@ class ModelScanner { if (nextElementType.equals(BoundCodeDt.class)) { IValueSetEnumBinder> binder = getBoundCodeBinder(next); def = new RuntimeChildPrimitiveBoundCodeDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binder); + } else if (IBaseEnumeration.class.isAssignableFrom(nextElementType)) { + Class binderType = ReflectionUtil.getGenericCollectionTypeOfField(next); + def = new RuntimeChildPrimitiveEnumerationDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binderType); } else if (childAnnotation.enumFactory().getSimpleName().equals("NoEnumFactory") == false) { Class> enumFactory = childAnnotation.enumFactory(); def = new RuntimeChildEnumerationDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, enumFactory); + // } else if ("id".equals(elementName) && IIdType.class.isAssignableFrom(nextDatatype)) { + // def = new RuntimeChildIdDatatypeDefinition(next, elementName, descriptionAnnotation, + // childAnnotation, nextDatatype); } else { def = new RuntimeChildPrimitiveDatatypeDefinition(next, elementName, descriptionAnnotation, childAnnotation, nextDatatype); } + } else if (IBaseXhtml.class.isAssignableFrom(nextElementType)) { + def = new RuntimeChildXhtmlDatatypeDefinition(next, elementName, descriptionAnnotation, childAnnotation, nextDatatype); } else { if (IBoundCodeableConcept.class.isAssignableFrom(nextElementType)) { IValueSetEnumBinder> binder = getBoundCodeBinder(next); def = new RuntimeChildCompositeBoundDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binder); - } else if (BaseNarrativeDt.class.isAssignableFrom(nextElementType) || INarrative.class.getName().equals(nextElementType.getClass().getName())) { + } else if (BaseNarrativeDt.class.isAssignableFrom(nextElementType) || INarrative.class.isAssignableFrom(nextElementType)) { def = new RuntimeChildNarrativeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype); } else { def = new RuntimeChildCompositeDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype); @@ -633,6 +644,12 @@ class ModelScanner { @SuppressWarnings("unchecked") Class clazz = (Class) theClass; resourceDef = new RuntimePrimitiveDatatypeNarrativeDefinition(resourceName, clazz); + } else if (IBaseXhtml.class.isAssignableFrom(theClass)) { + @SuppressWarnings("unchecked") + Class clazz = (Class) theClass; + resourceDef = new RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition(resourceName, clazz); + } else if (IIdType.class.isAssignableFrom(theClass)) { + resourceDef = new RuntimeIdDatatypeDefinition(theDatatypeDefinition, theClass); } else { resourceDef = new RuntimePrimitiveDatatypeDefinition(theDatatypeDefinition, theClass); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildContainedResources.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildContainedResources.java index 7cbab2e0d4a..d72bf5aa746 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildContainedResources.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildContainedResources.java @@ -21,12 +21,13 @@ package ca.uhn.fhir.context; */ import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Set; import org.hl7.fhir.instance.model.IBase; +import org.hl7.fhir.instance.model.IBaseResource; import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Description; @@ -34,7 +35,7 @@ import ca.uhn.fhir.model.base.composite.BaseContainedDt; public class RuntimeChildContainedResources extends BaseRuntimeDeclaredChildDefinition { - private RuntimeElemContainedResources myElem; + private BaseRuntimeElementDefinition myElem; RuntimeChildContainedResources(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException { super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName); @@ -48,13 +49,13 @@ public class RuntimeChildContainedResources extends BaseRuntimeDeclaredChildDefi @Override public BaseRuntimeElementDefinition getChildElementDefinitionByDatatype(Class theType) { - assert BaseContainedDt.class.isAssignableFrom(theType); + assert BaseContainedDt.class.isAssignableFrom(theType) || List.class.isAssignableFrom(theType); return myElem; } @Override - public String getChildNameByDatatype(Class theDatatype) { - assert BaseContainedDt.class.isAssignableFrom(theDatatype); + public String getChildNameByDatatype(Class theType) { + assert BaseContainedDt.class.isAssignableFrom(theType) || List.class.isAssignableFrom(theType); return getElementName(); } @@ -70,8 +71,8 @@ public class RuntimeChildContainedResources extends BaseRuntimeDeclaredChildDefi @SuppressWarnings("unchecked") Class type = (Class) actualType; myElem = new RuntimeElemContainedResources(type); - } else if (ArrayList.class.isAssignableFrom(actualType)) { - myElem = null; + } else if (List.class.isAssignableFrom(actualType)) { + myElem = new RuntimeElemContainedResourceList(IBaseResource.class); } else { throw new ConfigurationException("Fhir Version definition returned invalid contained type: " + actualType); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java index 41c00fe88b9..c8cce9728b3 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveBoundCodeDatatypeDefinition.java @@ -24,22 +24,21 @@ import java.lang.reflect.Field; import org.hl7.fhir.instance.model.IBase; -import ca.uhn.fhir.model.api.IValueSetEnumBinder; import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Description; public class RuntimeChildPrimitiveBoundCodeDatatypeDefinition extends RuntimeChildPrimitiveDatatypeDefinition { - private IValueSetEnumBinder> myBinder; + private Object myBinder; - public RuntimeChildPrimitiveBoundCodeDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, IValueSetEnumBinder> theBinder) { + public RuntimeChildPrimitiveBoundCodeDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, Object theBinder) { super(theField, theElementName, theDescriptionAnnotation, theChildAnnotation, theDatatype); myBinder = theBinder; } @Override - public IValueSetEnumBinder> getInstanceConstructorArguments() { + public Object getInstanceConstructorArguments() { return myBinder; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveDatatypeDefinition.java index 564aa30f333..a314d0339d3 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveDatatypeDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveDatatypeDefinition.java @@ -28,10 +28,47 @@ import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Description; public class RuntimeChildPrimitiveDatatypeDefinition extends BaseRuntimeChildDatatypeDefinition { - +// private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuntimeChildPrimitiveDatatypeDefinition.class); +// private IMutator myReferenceMutator; + public RuntimeChildPrimitiveDatatypeDefinition(Field theField, String theElementName, Description theDescriptionAnnotation, Child theChildAnnotation, Class theDatatype) { super(theField, theElementName, theChildAnnotation, theDescriptionAnnotation, theDatatype); } +// @Override +// void sealAndInitialize(FhirContext theContext, Map, BaseRuntimeElementDefinition> theClassToElementDefinitions) { +// super.sealAndInitialize(theContext, theClassToElementDefinitions); +// +// if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) { +// if (IReference.class.isAssignableFrom(getDatatype())) { +// String fieldName = getField().getName() + "Target"; +// try { +// Field targetField = getField().getDeclaringClass().getField(fieldName); +// if (List.class.isAssignableFrom(targetField.getType())) { +// myReferenceMutator = new FieldListMutator(); +// } else if (IBaseResource.class.isAssignableFrom(targetField.getType())) { +// myReferenceMutator = new FieldPlainMutator(); +// } +// } catch (Exception e) { +// ourLog.debug("Unable to find target field named {}", fieldName); +// } +// } +// } else { +// if (BaseResourceReferenceDt.class.isAssignableFrom(getDatatype())) { +// myReferenceMutator = new IMutator() { +// @Override +// public void addValue(Object theTarget, IBase theValue) { +// BaseResourceReferenceDt dt = (BaseResourceReferenceDt)theTarget; +// dt.setResource((IBaseResource) theValue); +// }}; +// } +// } +// +// } +// +// public IMutator getReferenceMutator() { +// return myReferenceMutator; +// } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveEnumerationDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveEnumerationDatatypeDefinition.java new file mode 100644 index 00000000000..b819c536b8a --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildPrimitiveEnumerationDatatypeDefinition.java @@ -0,0 +1,58 @@ +package ca.uhn.fhir.context; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.lang.reflect.Field; + +import org.hl7.fhir.instance.model.IBase; + +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; + +public class RuntimeChildPrimitiveEnumerationDatatypeDefinition extends RuntimeChildPrimitiveDatatypeDefinition { + + private Object myBinder; + private Class myEnumerationType; + + public RuntimeChildPrimitiveEnumerationDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class theDatatype, Class theBinderType) { + super(theField, theElementName, theDescriptionAnnotation, theChildAnnotation, theDatatype); + + myEnumerationType = theBinderType; + } + + @Override + public Object getInstanceConstructorArguments() { + Object retVal = myBinder; + if (retVal == null) { + Class clazz; + String className = myEnumerationType.getName() + "EnumFactory"; + try { + clazz = Class.forName(className); + retVal = clazz.newInstance(); + myBinder = retVal; + } catch (Exception e) { + throw new ConfigurationException("Failed to instantiate " + className, e); + } + } + return retVal; + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildResourceDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildResourceDefinition.java index 560f25732ae..3ee4b102d7c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildResourceDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildResourceDefinition.java @@ -31,6 +31,7 @@ import java.util.Set; import org.hl7.fhir.instance.model.IBase; import org.hl7.fhir.instance.model.IBaseResource; +import org.hl7.fhir.instance.model.api.IReference; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.annotation.Child; @@ -43,6 +44,9 @@ public class RuntimeChildResourceDefinition extends BaseRuntimeDeclaredChildDefi private List> myResourceTypes; private Set myValidChildNames; + /** + * Constructor + */ public RuntimeChildResourceDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, List> theResourceTypes) { super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName); myResourceTypes = theResourceTypes; @@ -56,7 +60,7 @@ public class RuntimeChildResourceDefinition extends BaseRuntimeDeclaredChildDefi @Override public String getChildNameByDatatype(Class theDatatype) { - if (BaseResourceReferenceDt.class.isAssignableFrom(theDatatype)) { + if (IReference.class.isAssignableFrom(theDatatype)) { return getElementName(); } return null; @@ -64,7 +68,7 @@ public class RuntimeChildResourceDefinition extends BaseRuntimeDeclaredChildDefi @Override public BaseRuntimeElementDefinition getChildElementDefinitionByDatatype(Class theDatatype) { - if (BaseResourceReferenceDt.class.isAssignableFrom(theDatatype)) { + if (IReference.class.isAssignableFrom(theDatatype)) { return myRuntimeDef; } return null; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildXhtmlDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildXhtmlDatatypeDefinition.java new file mode 100644 index 00000000000..2139cc0dfaa --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildXhtmlDatatypeDefinition.java @@ -0,0 +1,40 @@ +package ca.uhn.fhir.context; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.lang.reflect.Field; + +import org.hl7.fhir.instance.model.IBase; + +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; + +/** + * HL7org XHTML type + */ +public class RuntimeChildXhtmlDatatypeDefinition extends RuntimeChildPrimitiveDatatypeDefinition { + + public RuntimeChildXhtmlDatatypeDefinition(Field theField, String theElementName, Description theDescriptionAnnotation, Child theChildAnnotation, Class theDatatype) { + super(theField, theElementName, theDescriptionAnnotation, theChildAnnotation, theDatatype); + } + + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeElemContainedResourceList.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeElemContainedResourceList.java new file mode 100644 index 00000000000..d4018331902 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeElemContainedResourceList.java @@ -0,0 +1,42 @@ +package ca.uhn.fhir.context; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.List; + +import org.hl7.fhir.instance.model.IBaseResource; + +/** + * HL7org structures use a List for contained instead of a distinct datatype + */ +public class RuntimeElemContainedResourceList extends BaseRuntimeElementDefinition { + + public RuntimeElemContainedResourceList(Class theClass) { + super("contained", theClass); + assert List.class.isAssignableFrom(theClass); + } + + @Override + public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() { + return ChildTypeEnum.CONTAINED_RESOURCE_LIST; + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeIdDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeIdDatatypeDefinition.java new file mode 100644 index 00000000000..d4ca4a7c752 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeIdDatatypeDefinition.java @@ -0,0 +1,38 @@ +package ca.uhn.fhir.context; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import org.hl7.fhir.instance.model.IPrimitiveType; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +public class RuntimeIdDatatypeDefinition extends RuntimePrimitiveDatatypeDefinition implements IRuntimeDatatypeDefinition { + + public RuntimeIdDatatypeDefinition(DatatypeDef theDef, Class> theImplementingClass) { + super(theDef, theImplementingClass); + } + + @Override + public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() { + return ChildTypeEnum.ID_DATATYPE; + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimePrimitiveDatatypeDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimePrimitiveDatatypeDefinition.java index 9f4b7959713..daf06ecb5f9 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimePrimitiveDatatypeDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimePrimitiveDatatypeDefinition.java @@ -30,11 +30,11 @@ import org.hl7.fhir.instance.model.IPrimitiveType; import ca.uhn.fhir.model.api.annotation.DatatypeDef; import ca.uhn.fhir.model.api.annotation.ResourceDef; -public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition implements IRuntimeDatatypeDefinition { +public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition> implements IRuntimeDatatypeDefinition { private boolean mySpecialization; - public RuntimePrimitiveDatatypeDefinition(DatatypeDef theDef, Class theImplementingClass) { + public RuntimePrimitiveDatatypeDefinition(DatatypeDef theDef, Class> theImplementingClass) { super(theDef.name(), theImplementingClass); String resourceName = theDef.name(); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition.java new file mode 100644 index 00000000000..802991132e2 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition.java @@ -0,0 +1,44 @@ +package ca.uhn.fhir.context; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.Map; + +import org.hl7.fhir.instance.model.IBase; +import org.hl7.fhir.instance.model.api.IBaseXhtml; + +public class RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition extends BaseRuntimeElementDefinition { + + public RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition(String theName, Class theImplementingClass) { + super(theName, theImplementingClass); + } + + @Override + public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() { + return ChildTypeEnum.PRIMITIVE_XHTML_HL7ORG; + } + + @Override + void sealAndInitialize(FhirContext theContext, Map, BaseRuntimeElementDefinition> theClassToElementDefinitions) { + // nothing + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceReferenceDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceReferenceDefinition.java index 74fa2222b9e..73394d0526b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceReferenceDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeResourceReferenceDefinition.java @@ -36,6 +36,9 @@ public class RuntimeResourceReferenceDefinition extends BaseRuntimeElementDefini private final List> myResourceTypes; private HashMap, RuntimeResourceDefinition> myResourceTypeToDefinition; + /** + * Constructor + */ public RuntimeResourceReferenceDefinition(String theName, List> theResourceTypes) { super(theName, BaseResourceReferenceDt.class); if (theResourceTypes == null || theResourceTypes.isEmpty()) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseResourceReferenceDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseResourceReferenceDt.java index 37186c7c505..814125790a9 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseResourceReferenceDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseResourceReferenceDt.java @@ -28,6 +28,7 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.hl7.fhir.instance.model.api.IBaseDatatype; +import org.hl7.fhir.instance.model.api.IReference; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.BaseIdentifiableElement; @@ -38,7 +39,7 @@ import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.rest.client.BaseClient; import ca.uhn.fhir.rest.client.api.IRestfulClient; -public abstract class BaseResourceReferenceDt extends BaseIdentifiableElement implements IBaseDatatype { +public abstract class BaseResourceReferenceDt extends BaseIdentifiableElement implements IBaseDatatype, IReference { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseResourceReferenceDt.class); private IResource myResource; @@ -114,7 +115,7 @@ public abstract class BaseResourceReferenceDt extends BaseIdentifiableElement im IParser parser = context.newXmlParser(); Reader responseReader = BaseClient.createReaderFromResponse(response); - myResource = parser.parseResource(responseReader); + myResource = (IResource) parser.parseResource(responseReader); } finally { if (response instanceof CloseableHttpResponse) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java index 2d3a0bf8558..e9c34f47ddd 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java @@ -30,6 +30,7 @@ import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.hl7.fhir.instance.model.IBaseResource; import org.hl7.fhir.instance.model.api.IAnyResource; +import org.hl7.fhir.instance.model.api.IIdType; import ca.uhn.fhir.model.api.IPrimitiveDatatype; import ca.uhn.fhir.model.api.IResource; @@ -51,7 +52,7 @@ import ca.uhn.fhir.util.UrlUtil; *

*/ @DatatypeDef(name = "id") -public class IdDt extends UriDt implements IPrimitiveDatatype { +public class IdDt extends UriDt implements IPrimitiveDatatype, IIdType { private String myBaseUrl; private boolean myHaveComponentParts; @@ -229,6 +230,11 @@ public class IdDt extends UriDt implements IPrimitiveDatatype { return myBaseUrl; } + /** + * Returns only the logical ID part of this ID. For example, given the ID + * "http://example,.com/fhir/Patient/123/_history/456", this method would + * return "123". + */ public String getIdPart() { return myUnqualifiedId; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java index a652451e07b..c330534a289 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java @@ -20,8 +20,7 @@ package ca.uhn.fhir.parser; * #L% */ -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.io.IOException; import java.io.Reader; @@ -43,11 +42,14 @@ import org.hl7.fhir.instance.model.IBaseResource; import org.hl7.fhir.instance.model.IPrimitiveType; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IReference; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition; import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.RuntimeChildChoiceDefinition; @@ -57,16 +59,14 @@ import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TagList; -import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; import ca.uhn.fhir.model.primitive.IdDt; public abstract class BaseParser implements IParser { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class); private ContainedResources myContainedResources; private FhirContext myContext; - private boolean mySuppressNarratives; private String myServerBaseUrl; + private boolean mySuppressNarratives; public BaseParser(FhirContext theContext) { myContext = theContext; @@ -95,8 +95,11 @@ public abstract class BaseParser implements IParser { } else if (theTarget instanceof IDomainResource) { List containedResources = ((IDomainResource) theTarget).getContained(); for (IAnyResource next : containedResources) { - String nextId = next.getId(); + String nextId = next.getId().getValue(); if (StringUtils.isNotBlank(nextId)) { + if (!nextId.startsWith("#")) { + nextId = '#' + nextId; + } allIds.add(nextId); if (existingIdToContainedResource == null) { existingIdToContainedResource = new HashMap(); @@ -109,9 +112,9 @@ public abstract class BaseParser implements IParser { } { - List allElements = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, BaseResourceReferenceDt.class); - for (BaseResourceReferenceDt next : allElements) { - IResource resource = next.getResource(); + List allElements = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, IReference.class); + for (IReference next : allElements) { + IBaseResource resource = next.getResource(); if (resource != null) { if (resource.getId().isEmpty() || resource.getId().isLocal()) { theContained.addContained(resource); @@ -132,44 +135,21 @@ public abstract class BaseParser implements IParser { } } - { - List allElements = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, IReference.class); - for (IReference next : allElements) { - IAnyResource resource = next.getResource(); - if (resource != null) { - if (resource.getIdElement().isEmpty() || resource.getId().startsWith("#")) { - theContained.addContained(resource); - } else { - continue; - } - - containResourcesForEncoding(theContained, resource, theTarget); - } else if (next.getReference() != null && next.getReference().startsWith("#")) { - if (existingIdToContainedResource != null) { - IBaseResource potentialTarget = existingIdToContainedResource.remove(next.getReference()); - if (potentialTarget != null) { - theContained.addContained(potentialTarget); - containResourcesForEncoding(theContained, potentialTarget, theTarget); - } - } - } - } - } - } + protected void containResourcesForEncoding(IBaseResource theResource) { ContainedResources contained = new ContainedResources(); containResourcesForEncoding(contained, theResource, theResource); myContainedResources = contained; } - protected String determineReferenceText(BaseResourceReferenceDt theRef) { - IdDt ref = theRef.getReference(); + protected String determineReferenceText(IReference theRef) { + IIdType ref = theRef.getReference(); if (isBlank(ref.getIdPart())) { String reference = ref.getValue(); if (theRef.getResource() != null) { - IdDt containedId = getContainedResources().getResourceId(theRef.getResource()); + IIdType containedId = getContainedResources().getResourceId(theRef.getResource()); if (containedId != null && !containedId.isEmpty()) { if (containedId.isLocal()) { reference = containedId.getValue(); @@ -192,12 +172,6 @@ public abstract class BaseParser implements IParser { } } - @Override - public IParser setServerBaseUrl(String theUrl) { - myServerBaseUrl = isNotBlank(theUrl) ? theUrl : null; - return this; - } - protected String determineResourceBaseUrl(String bundleBaseUrl, BundleEntry theEntry) { IResource resource = theEntry.getResource(); if (resource == null) { @@ -270,6 +244,10 @@ public abstract class BaseParser implements IParser { return mySuppressNarratives; } + protected boolean isChildContained(BaseRuntimeElementDefinition childDef, boolean theIncludedResource) { + return (childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES || childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCE_LIST) && getContainedResources().isEmpty() == false && theIncludedResource == false; + } + @Override public Bundle parseBundle(Reader theReader) { return parseBundle(null, theReader); @@ -337,12 +315,12 @@ public abstract class BaseParser implements IParser { } @Override - public IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException { + public IBaseResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException { return parseResource(null, theReader); } @Override - public IResource parseResource(String theMessageString) throws ConfigurationException, DataFormatException { + public IBaseResource parseResource(String theMessageString) throws ConfigurationException, DataFormatException { return parseResource(null, theMessageString); } @@ -351,6 +329,12 @@ public abstract class BaseParser implements IParser { return parseTagList(new StringReader(theString)); } + @Override + public IParser setServerBaseUrl(String theUrl) { + myServerBaseUrl = isNotBlank(theUrl) ? theUrl : null; + return this; + } + @Override public IParser setSuppressNarratives(boolean theSuppressNarratives) { mySuppressNarratives = theSuppressNarratives; @@ -385,18 +369,16 @@ public abstract class BaseParser implements IParser { private long myNextContainedId = 1; private List myResources = new ArrayList(); - private IdentityHashMap myResourceToId = new IdentityHashMap(); + private IdentityHashMap myResourceToId = new IdentityHashMap(); public void addContained(IBaseResource theResource) { if (myResourceToId.containsKey(theResource)) { return; } - IdDt newId; - if (theResource instanceof IResource && ((IResource) theResource).getId().isLocal()) { - newId = ((IResource) theResource).getId(); - } else if (theResource instanceof IAnyResource && ((IAnyResource) theResource).getId() != null && ((IAnyResource) theResource).getId().startsWith("#")) { - newId = new IdDt(((IAnyResource) theResource).getId()); + IIdType newId; + if (theResource.getId().isLocal()) { + newId = theResource.getId(); } else { // TODO: make this configurable between the two below (and something else?) // newId = new IdDt(UUID.randomUUID().toString()); @@ -407,7 +389,7 @@ public abstract class BaseParser implements IParser { myResources.add(theResource); } - public void addContained(IdDt theId, IBaseResource theResource) { + public void addContained(IIdType theId, IBaseResource theResource) { myResourceToId.put(theResource, theId); myResources.add(theResource); } @@ -416,7 +398,7 @@ public abstract class BaseParser implements IParser { return myResources; } - public IdDt getResourceId(IBaseResource theNext) { + public IIdType getResourceId(IBaseResource theNext) { return myResourceToId.get(theNext); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java index 1ca5680bab5..9b597e1f59f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java @@ -123,7 +123,7 @@ public interface IParser { * @throws DataFormatException * If the resource can not be parsed because the data is not recognized or invalid for any reason */ - IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException; + IBaseResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException; /** * Parses a resource @@ -134,7 +134,7 @@ public interface IParser { * @throws DataFormatException * If the resource can not be parsed because the data is not recognized or invalid for any reason */ - IResource parseResource(String theMessageString) throws ConfigurationException, DataFormatException; + IBaseResource parseResource(String theMessageString) throws ConfigurationException, DataFormatException; /** * Parses a tag list, as defined in the FHIR Specification. diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index b30990034c7..5b5fdfe2c62 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -63,6 +63,7 @@ import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseHasExtensions; import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; import org.hl7.fhir.instance.model.api.IBaseIntegerDatatype; +import org.hl7.fhir.instance.model.api.IIdType; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; @@ -103,8 +104,8 @@ import ca.uhn.fhir.util.ElementUtil; import ca.uhn.fhir.util.UrlUtil; /** - * This class is the FHIR JSON parser/encoder. Users should not interact with this - * class directly, but should use {@link FhirContext#newJsonParser()} to get an instance. + * This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use + * {@link FhirContext#newJsonParser()} to get an instance. */ public class JsonParser extends BaseParser implements IParser { @@ -131,7 +132,8 @@ public class JsonParser extends BaseParser implements IParser { private boolean myPrettyPrint; /** - * Do not use this constructor, the recommended way to obtain a new instance of the JSON parser is to invoke {@link FhirContext#newJsonParser()}. + * Do not use this constructor, the recommended way to obtain a new instance of the JSON parser is to invoke + * {@link FhirContext#newJsonParser()}. */ public JsonParser(FhirContext theContext) { super(theContext); @@ -323,8 +325,10 @@ public class JsonParser extends BaseParser implements IParser { // linkStarted = false; // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "self", nextEntry.getLinkSelf(), linkStarted); - // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "alternate", nextEntry.getLinkAlternate(), linkStarted); - // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "search", nextEntry.getLinkSearch(), linkStarted); + // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "alternate", nextEntry.getLinkAlternate(), + // linkStarted); + // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "search", nextEntry.getLinkSearch(), + // linkStarted); // if (linkStarted) { // theEventWriter.writeEnd(); // } @@ -347,10 +351,21 @@ public class JsonParser extends BaseParser implements IParser { theEventWriter.writeEnd(); } - private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, - BaseRuntimeElementDefinition theChildDef, String theChildName, boolean theIsSubElementWithinResource) throws IOException { + private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, BaseRuntimeElementDefinition theChildDef, String theChildName, boolean theIsSubElementWithinResource) throws IOException { switch (theChildDef.getChildType()) { + case ID_DATATYPE: { + IIdType value = (IIdType) theNextValue; + if (isBlank(value.getIdPart())) { + break; + } + if (theChildName != null) { + theWriter.write(theChildName, value.getIdPart()); + } else { + theWriter.write(value.getIdPart()); + } + break; + } case PRIMITIVE_DATATYPE: { IPrimitiveType value = (IPrimitiveType) theNextValue; if (isBlank(value.getValueAsString())) { @@ -419,17 +434,20 @@ public class JsonParser extends BaseParser implements IParser { theWriter.writeEnd(); break; } + case CONTAINED_RESOURCE_LIST: case CONTAINED_RESOURCES: { /* - * Disabled per #103 ContainedDt value = (ContainedDt) theNextValue; for (IResource next : value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { - * continue; } encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null, true, fixContainedResourceId(next.getId().getValue())); } + * Disabled per #103 ContainedDt value = (ContainedDt) theNextValue; for (IResource next : + * value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { continue; } + * encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null, true, + * fixContainedResourceId(next.getId().getValue())); } */ List containedResources = getContainedResources().getContainedResources(); if (containedResources.size() > 0) { theWriter.writeStartArray(theChildName); for (IBaseResource next : containedResources) { - IdDt resourceId = getContainedResources().getResourceId(next); + IIdType resourceId = getContainedResources().getResourceId(next); encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null, true, fixContainedResourceId(resourceId.getValue())); } @@ -437,9 +455,10 @@ public class JsonParser extends BaseParser implements IParser { } break; } + case PRIMITIVE_XHTML_HL7ORG: case PRIMITIVE_XHTML: { if (!getSuppressNarratives()) { - XhtmlDt dt = (XhtmlDt) theNextValue; + IPrimitiveType dt = (IPrimitiveType) theNextValue; if (theChildName != null) { theWriter.write(theChildName, dt.getValueAsString()); } else { @@ -466,13 +485,12 @@ public class JsonParser extends BaseParser implements IParser { } - private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, - List theChildren, boolean theIsSubElementWithinResource) throws IOException { + private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, List theChildren, boolean theIsSubElementWithinResource) throws IOException { for (BaseRuntimeChildDefinition nextChild : theChildren) { if (nextChild.getElementName().equals("extension") || nextChild.getElementName().equals("modifierExtension")) { continue; } - + if (nextChild instanceof RuntimeChildNarrativeDefinition) { INarrativeGenerator gen = myContext.getNarrativeGenerator(); @@ -520,7 +538,7 @@ public class JsonParser extends BaseParser implements IParser { } boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE; - if (childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES && theIsSubElementWithinResource) { + if ((childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES||childDef.getChildType()==ChildTypeEnum.CONTAINED_RESOURCE_LIST) && theIsSubElementWithinResource) { continue; } @@ -624,15 +642,13 @@ public class JsonParser extends BaseParser implements IParser { } } - private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, - BaseRuntimeElementCompositeDefinition resDef, boolean theIsSubElementWithinResource) throws IOException, DataFormatException { + private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition resDef, boolean theIsSubElementWithinResource) throws IOException, DataFormatException { extractAndWriteExtensionsAsDirectChild(theNextValue, theEventWriter, resDef, theResDef, theResource, null); encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theIsSubElementWithinResource); encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theIsSubElementWithinResource); } - private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, - boolean theContainedResource) throws IOException { + private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource) throws IOException { String resourceId = null; if (theResource instanceof IResource) { IResource res = (IResource) theResource; @@ -645,16 +661,15 @@ public class JsonParser extends BaseParser implements IParser { } } else if (theResource instanceof IAnyResource) { IAnyResource res = (IAnyResource) theResource; - if (theContainedResource && StringUtils.isNotBlank(res.getId())) { - resourceId = res.getId(); + if (StringUtils.isNotBlank(res.getId().getIdPart())) { + resourceId = res.getId().getIdPart(); } } encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theContainedResource, resourceId); } - private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, - boolean theContainedResource, String theResourceId) throws IOException { + private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource, String theResourceId) throws IOException { if (!theContainedResource) { super.containResourcesForEncoding(theResource); } @@ -688,8 +703,8 @@ public class JsonParser extends BaseParser implements IParser { theEventWriter.writeStartObject("meta"); writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart()); writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource)); - - if (profiles != null && profiles.isEmpty()==false) { + + if (profiles != null && profiles.isEmpty() == false) { theEventWriter.writeStartArray("profile"); for (IdDt profile : profiles) { if (profile != null && isNotBlank(profile.getValue())) { @@ -699,7 +714,7 @@ public class JsonParser extends BaseParser implements IParser { theEventWriter.writeEnd(); } - if (securityLabels.isEmpty()==false) { + if (securityLabels.isEmpty() == false) { theEventWriter.writeStartArray("security"); for (BaseCodingDt securityLabel : securityLabels) { theEventWriter.writeStartObject(); @@ -709,8 +724,8 @@ public class JsonParser extends BaseParser implements IParser { } theEventWriter.writeEnd(); } - - if (tags != null && tags.isEmpty()==false) { + + if (tags != null && tags.isEmpty() == false) { theEventWriter.writeStartArray("tag"); for (Tag tag : tags) { theEventWriter.writeStartObject(); @@ -722,7 +737,7 @@ public class JsonParser extends BaseParser implements IParser { theEventWriter.writeEnd(); } - theEventWriter.writeEnd(); //end meta + theEventWriter.writeEnd(); // end meta } } @@ -779,10 +794,10 @@ public class JsonParser extends BaseParser implements IParser { } /** - * This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object called _name): resource extensions, and extension extensions + * This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object + * called _name): resource extensions, and extension extensions */ - private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonGenerator theEventWriter, BaseRuntimeElementDefinition theElementDef, RuntimeResourceDefinition theResDef, - IBaseResource theResource, String theParentExtensionUrl) throws IOException { + private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonGenerator theEventWriter, BaseRuntimeElementDefinition theElementDef, RuntimeResourceDefinition theResDef, IBaseResource theResource, String theParentExtensionUrl) throws IOException { List extensions = new ArrayList(0); List modifierExtensions = new ArrayList(0); @@ -916,8 +931,7 @@ public class JsonParser extends BaseParser implements IParser { object = reader.readObject(); } catch (JsonParsingException e) { if (e.getMessage().startsWith("Unexpected char 39")) { - throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage() - + " - This may indicate that single quotes are being used as JSON escapes where double quotes are required", e); + throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage() + " - This may indicate that single quotes are being used as JSON escapes where double quotes are required", e); } throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage(), e); } @@ -1154,7 +1168,8 @@ public class JsonParser extends BaseParser implements IParser { JsonValue jsonVal = nextExt.get(nextKey); if (jsonVal.getValueType() == ValueType.ARRAY) { /* - * Extension children which are arrays are sub-extensions. Any other value type should be treated as a value. + * Extension children which are arrays are sub-extensions. Any other value type should be treated as + * a value. */ JsonArray arrayValue = (JsonArray) jsonVal; parseExtensionInDstu2Style(theModifier, theState, extUrl, nextKey, arrayValue); @@ -1278,8 +1293,7 @@ public class JsonParser extends BaseParser implements IParser { } } - private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List extensions, - List modifierExtensions, String theParentExtensionUrl) throws IOException { + private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List extensions, List modifierExtensions, String theParentExtensionUrl) throws IOException { if (extensions.isEmpty() == false) { theEventWriter.writeStartArray("extension"); for (HeldExtension next : extensions) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index edce214a543..ccb29a4caf5 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -41,6 +41,7 @@ import org.hl7.fhir.instance.model.api.IBaseElement; import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseHasExtensions; import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; +import org.hl7.fhir.instance.model.api.IBaseXhtml; import org.hl7.fhir.instance.model.api.IReference; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; @@ -53,6 +54,7 @@ import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition; import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition; import ca.uhn.fhir.context.RuntimePrimitiveDatatypeNarrativeDefinition; +import ca.uhn.fhir.context.RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition; import ca.uhn.fhir.context.RuntimeResourceBlockDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.model.api.BaseBundle; @@ -1367,6 +1369,37 @@ class ParserState { } + private class ContainedResourcesStateHl7Org extends PreResourceState { + + public ContainedResourcesStateHl7Org(PreResourceState thePreResourcesState) { + super(thePreResourcesState, FhirVersionEnum.DSTU2_HL7ORG); + } + + @Override + public void endingElement() throws DataFormatException { + pop(); + } + + @Override + public void wereBack() { + IBaseResource res = getCurrentElement(); + assert res != null; + if (res.getId() == null || res.getId().isEmpty()) { + ourLog.debug("Discarding contained resource with no ID!"); + } else { + getPreResourceState().getContainedResources().put(res.getId().getValue(), res); + if (!res.getId().isLocal()) { + res.getId().setValue('#' + res.getId().getIdPart()); + } + } + + IBaseResource preResCurrentElement = getPreResourceState().getCurrentElement(); + RuntimeResourceDefinition def = myContext.getResourceDefinition(preResCurrentElement); + def.getChildByName("contained").getMutator().addValue(preResCurrentElement, res); + } + + } + private class DeclaredExtensionState extends BaseState { private IBase myChildInstance; @@ -1396,7 +1429,7 @@ class ParserState { switch (target.getChildType()) { case COMPOSITE_DATATYPE: { BaseRuntimeElementCompositeDefinition compositeTarget = (BaseRuntimeElementCompositeDefinition) target; - ICompositeDatatype newChildInstance = (ICompositeDatatype) compositeTarget.newInstance(myDefinition.getInstanceConstructorArguments()); + ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(myDefinition.getInstanceConstructorArguments()); myDefinition.getMutator().addValue(myParentInstance, newChildInstance); ElementCompositeState newState = new ElementCompositeState(myPreResourceState, compositeTarget, newChildInstance); push(newState); @@ -1525,6 +1558,7 @@ class ParserState { push(newState); return; } + case ID_DATATYPE: case PRIMITIVE_DATATYPE: { RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target; IPrimitiveType newChildInstance; @@ -1557,6 +1591,14 @@ class ParserState { push(state); return; } + case PRIMITIVE_XHTML_HL7ORG: { + RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition xhtmlTarget = (RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition) target; + IBaseXhtml newDt = xhtmlTarget.newInstance(); + child.getMutator().addValue(myInstance, newDt); + XhtmlStateHl7Org state = new XhtmlStateHl7Org(getPreResourceState(), newDt); + push(state); + return; + } case CONTAINED_RESOURCES: { List values = child.getAccessor().getValues(myInstance); Object newDt; @@ -1570,6 +1612,11 @@ class ParserState { push(state); return; } + case CONTAINED_RESOURCE_LIST: { + ContainedResourcesStateHl7Org state = new ContainedResourcesStateHl7Org(getPreResourceState()); + push(state); + return; + } case RESOURCE: { if (myInstance instanceof IResource) { ParserState.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null); @@ -1650,10 +1697,15 @@ class ParserState { return; } case RESOURCE_REF: { - BaseResourceReferenceDt newChildInstance = (BaseResourceReferenceDt) newResourceReferenceDt(getPreResourceState().myInstance); + ICompositeType newChildInstance = (ICompositeType) newResourceReferenceDt(getPreResourceState().myInstance); myExtension.setValue(newChildInstance); - ResourceReferenceStateHapi newState = new ResourceReferenceStateHapi(getPreResourceState(), newChildInstance); - push(newState); + if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) { + ParserState.ResourceReferenceStateHl7Org newState = new ResourceReferenceStateHl7Org(getPreResourceState(), (IReference) newChildInstance); + push(newState); + } else { + ResourceReferenceStateHapi newState = new ResourceReferenceStateHapi(getPreResourceState(), (BaseResourceReferenceDt) newChildInstance); + push(newState); + } return; } case PRIMITIVE_XHTML: @@ -2015,6 +2067,19 @@ class ParserState { } } } + }else if (theElement instanceof IReference) { + IReference nextRef = (IReference) theElement; + String ref = nextRef.getReference().getValue(); + if (isNotBlank(ref)) { + if (ref.startsWith("#")) { + IBaseResource target = myContainedResources.get(ref.substring(1)); + if (target != null) { + nextRef.setResource(target); + } else { + ourLog.warn("Resource contains unknown local ref: " + ref); + } + } + } } } @@ -2454,6 +2519,26 @@ class ParserState { } + private class XhtmlStateHl7Org extends XhtmlState { + private IBaseXhtml myHl7OrgDatatype; + + private XhtmlStateHl7Org(PreResourceState thePreResourceState, IBaseXhtml theHl7OrgDatatype) { + super(thePreResourceState, new XhtmlDt(), true); + myHl7OrgDatatype = theHl7OrgDatatype; + } + + @Override + public void doPop() { + // TODO: this is not very efficient + String value = getDt().getValueAsString(); + myHl7OrgDatatype.setValueAsString(value); + + super.doPop(); + } + + + } + private class XhtmlState extends BaseState { private int myDepth; private XhtmlDt myDt; @@ -2467,6 +2552,10 @@ class ParserState { myIncludeOuterEvent = theIncludeOuterEvent; } + public XhtmlDt getDt() { + return myDt; + } + @Override public void attributeValue(String theName, String theValue) throws DataFormatException { if (myJsonMode) { @@ -2476,10 +2565,14 @@ class ParserState { super.attributeValue(theName, theValue); } + protected void doPop() { + pop(); + } + @Override public void endingElement() throws DataFormatException { if (myJsonMode) { - pop(); + doPop(); return; } super.endingElement(); @@ -2507,7 +2600,7 @@ class ParserState { if (theEvent.isEndElement()) { if (myDepth == 0) { myDt.setValue(myEvents); - pop(); + doPop(); } } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index 21c04ac451c..b36786e2107 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -56,8 +56,11 @@ import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseHasExtensions; import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; +import org.hl7.fhir.instance.model.api.IBaseXhtml; import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.INarrative; +import org.hl7.fhir.instance.model.api.IReference; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; @@ -66,6 +69,7 @@ import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.context.RuntimeChildContainedResources; import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition; import ca.uhn.fhir.context.RuntimeChildNarrativeDefinition; import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition; @@ -93,11 +97,11 @@ import ca.uhn.fhir.util.PrettyPrintWriterWrapper; import ca.uhn.fhir.util.XmlUtil; /** - * This class is the FHIR XML parser/encoder. Users should not interact with this - * class directly, but should use {@link FhirContext#newXmlParser()} to get an instance. + * This class is the FHIR XML parser/encoder. Users should not interact with this class directly, but should use + * {@link FhirContext#newXmlParser()} to get an instance. */ public class XmlParser extends BaseParser implements IParser { - + static final String ATOM_NS = "http://www.w3.org/2005/Atom"; static final String FHIR_NS = "http://hl7.org/fhir"; static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearch/1.1/"; @@ -113,7 +117,8 @@ public class XmlParser extends BaseParser implements IParser { private boolean myPrettyPrint; /** - * Do not use this constructor, the recommended way to obtain a new instance of the XML parser is to invoke {@link FhirContext#newXmlParser()}. + * Do not use this constructor, the recommended way to obtain a new instance of the XML parser is to invoke + * {@link FhirContext#newXmlParser()}. */ public XmlParser(FhirContext theContext) { super(theContext); @@ -442,10 +447,9 @@ public class XmlParser extends BaseParser implements IParser { theEventWriter.close(); } - private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition childDef, - String theExtensionUrl, boolean theIncludedResource) throws XMLStreamException, DataFormatException { - if (nextValue.isEmpty()) { - if (childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES && getContainedResources().isEmpty() == false && theIncludedResource == false) { + private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition childDef, String theExtensionUrl, boolean theIncludedResource) throws XMLStreamException, DataFormatException { + if (nextValue == null || nextValue.isEmpty()) { + if (isChildContained(childDef, theIncludedResource)) { // We still want to go in.. } else { return; @@ -453,6 +457,17 @@ public class XmlParser extends BaseParser implements IParser { } switch (childDef.getChildType()) { + case ID_DATATYPE: { + IIdType pd = (IIdType) nextValue; + String value = pd.getIdPart(); + if (value != null) { + theEventWriter.writeStartElement(childName); + theEventWriter.writeAttribute("value", value); + encodeExtensionsIfPresent(theResource, theEventWriter, nextValue, theIncludedResource); + theEventWriter.writeEndElement(); + } + break; + } case PRIMITIVE_DATATYPE: { IPrimitiveType pd = (IPrimitiveType) nextValue; String value = pd.getValueAsString(); @@ -476,7 +491,7 @@ public class XmlParser extends BaseParser implements IParser { break; } case RESOURCE_REF: { - BaseResourceReferenceDt ref = (BaseResourceReferenceDt) nextValue; + IReference ref = (IReference) nextValue; if (!ref.isEmpty()) { theEventWriter.writeStartElement(childName); encodeResourceReferenceToStreamWriter(theEventWriter, ref); @@ -484,15 +499,16 @@ public class XmlParser extends BaseParser implements IParser { } break; } + case CONTAINED_RESOURCE_LIST: case CONTAINED_RESOURCES: { - BaseContainedDt value = (BaseContainedDt) nextValue; /* - * Disable per #103 for (IResource next : value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { continue; } - * theEventWriter.writeStartElement("contained"); encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(next.getId().getValue())); - * theEventWriter.writeEndElement(); } + * Disable per #103 for (IResource next : value.getContainedResources()) { if + * (getContainedResources().getResourceId(next) != null) { continue; } + * theEventWriter.writeStartElement("contained"); encodeResourceToXmlStreamWriter(next, theEventWriter, + * true, fixContainedResourceId(next.getId().getValue())); theEventWriter.writeEndElement(); } */ for (IBaseResource next : getContainedResources().getContainedResources()) { - IdDt resourceId = getContainedResources().getResourceId(next); + IIdType resourceId = getContainedResources().getResourceId(next); theEventWriter.writeStartElement("contained"); encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(resourceId.getValue())); theEventWriter.writeEndElement(); @@ -513,6 +529,18 @@ public class XmlParser extends BaseParser implements IParser { } break; } + case PRIMITIVE_XHTML_HL7ORG: { + IBaseXhtml dt = (IBaseXhtml) nextValue; + if (dt.isEmpty()) { + break; + } else { + // TODO: this is probably not as efficient as it could be + XhtmlDt hdt = new XhtmlDt(); + hdt.setValueAsString(dt.getValueAsString()); + encodeXhtml(hdt, theEventWriter); + break; + } + } case EXTENSION_DECLARED: case UNDECL_EXT: { throw new IllegalStateException("state should not happen: " + childDef.getName()); @@ -521,12 +549,14 @@ public class XmlParser extends BaseParser implements IParser { } - private void encodeCompositeElementChildrenToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List children, - boolean theIncludedResource) throws XMLStreamException, DataFormatException { + private void encodeCompositeElementChildrenToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List children, boolean theIncludedResource) throws XMLStreamException, DataFormatException { for (BaseRuntimeChildDefinition nextChild : children) { if (nextChild.getElementName().equals("extension") || nextChild.getElementName().equals("modifierExtension")) { continue; } + if (nextChild.getElementName().equals("id")) { + continue; + } if (nextChild instanceof RuntimeChildNarrativeDefinition && !theIncludedResource) { INarrativeGenerator gen = myContext.getNarrativeGenerator(); @@ -544,67 +574,74 @@ public class XmlParser extends BaseParser implements IParser { continue; } } else { - INarrative narr1 = ((IDomainResource) theResource).getText(); - BaseNarrativeDt narr2 = null; - if (gen != null && narr1.isEmpty()) { - // TODO: need to implement this - String resourceProfile = myContext.getResourceDefinition(theResource).getResourceProfile(); - gen.generateNarrative(resourceProfile, theResource, null); - } - if (narr2 != null) { - RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild; - String childName = nextChild.getChildNameByDatatype(child.getDatatype()); - BaseRuntimeElementDefinition type = child.getChildByName(childName); - encodeChildElementToStreamWriter(theResource, theEventWriter, narr2, childName, type, null, theIncludedResource); - continue; - } + // Narrative generation not currently supported for HL7org structures +// INarrative narr1 = ((IDomainResource) theResource).getText(); +// BaseNarrativeDt narr2 = null; +// if (gen != null && narr1.isEmpty()) { +// // TODO: need to implement this +// String resourceProfile = myContext.getResourceDefinition(theResource).getResourceProfile(); +// gen.generateNarrative(resourceProfile, theResource, null); +// } +// if (narr2 != null) { +// RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild; +// String childName = nextChild.getChildNameByDatatype(child.getDatatype()); +// BaseRuntimeElementDefinition type = child.getChildByName(childName); +// encodeChildElementToStreamWriter(theResource, theEventWriter, narr2, childName, type, null, theIncludedResource); +// continue; +// } } } - List values = nextChild.getAccessor().getValues(theElement); - if (values == null || values.isEmpty()) { - continue; - } - for (IBase nextValue : values) { - if ((nextValue == null || nextValue.isEmpty()) && !(nextValue instanceof BaseContainedDt)) { + if (nextChild instanceof RuntimeChildContainedResources) { + if (!theIncludedResource) { + encodeChildElementToStreamWriter(theResource, theEventWriter, null, nextChild.getChildNameByDatatype(null), nextChild.getChildElementDefinitionByDatatype(null), null, theIncludedResource); + } + } else { + + List values = nextChild.getAccessor().getValues(theElement); + if (values == null || values.isEmpty()) { continue; } - Class type = nextValue.getClass(); - String childName = nextChild.getChildNameByDatatype(type); - String extensionUrl = nextChild.getExtensionUrl(); - BaseRuntimeElementDefinition childDef = nextChild.getChildElementDefinitionByDatatype(type); - if (childDef == null) { - super.throwExceptionForUnknownChildType(nextChild, type); - } - - if (nextValue instanceof IBaseExtension && myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) { - // This is called for the Query resource in DSTU1 only - extensionUrl = ((IBaseExtension) nextValue).getUrl(); - encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource); - - } else if (extensionUrl != null && childName.equals("extension") == false) { - RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild; - if (extDef.isModifier()) { - theEventWriter.writeStartElement("modifierExtension"); - } else { - theEventWriter.writeStartElement("extension"); + for (IBase nextValue : values) { + if ((nextValue == null || nextValue.isEmpty())) { + continue; + } + Class type = nextValue.getClass(); + String childName = nextChild.getChildNameByDatatype(type); + String extensionUrl = nextChild.getExtensionUrl(); + BaseRuntimeElementDefinition childDef = nextChild.getChildElementDefinitionByDatatype(type); + if (childDef == null) { + super.throwExceptionForUnknownChildType(nextChild, type); } - theEventWriter.writeAttribute("url", extensionUrl); - encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, null, theIncludedResource); - theEventWriter.writeEndElement(); - } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theIncludedResource) { - // suppress narratives from contained resources - } else { - encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource); + if (nextValue instanceof IBaseExtension && myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) { + // This is called for the Query resource in DSTU1 only + extensionUrl = ((IBaseExtension) nextValue).getUrl(); + encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource); + + } else if (extensionUrl != null && childName.equals("extension") == false) { + RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild; + if (extDef.isModifier()) { + theEventWriter.writeStartElement("modifierExtension"); + } else { + theEventWriter.writeStartElement("extension"); + } + + theEventWriter.writeAttribute("url", extensionUrl); + encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, null, theIncludedResource); + theEventWriter.writeEndElement(); + } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theIncludedResource) { + // suppress narratives from contained resources + } else { + encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource); + } } } } } - private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition theElementDefinition, - boolean theIncludedResource) throws XMLStreamException, DataFormatException { + private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition theElementDefinition, boolean theIncludedResource) throws XMLStreamException, DataFormatException { encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource); encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getExtensions(), theIncludedResource); encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getChildren(), theIncludedResource); @@ -627,8 +664,9 @@ public class XmlParser extends BaseParser implements IParser { } /** - * This is just to work around the fact that casting java.util.List to java.util.List> seems to be - * rejected by the compiler some of the time. + * This is just to work around the fact that casting java.util.List to + * java.util.List> seems to be rejected by the compiler + * some of the time. */ private > List> toBaseExtensionList(final List theList) { List> retVal = new ArrayList>(theList.size()); @@ -636,7 +674,7 @@ public class XmlParser extends BaseParser implements IParser { return retVal; } - private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, BaseResourceReferenceDt theRef) throws XMLStreamException { + private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, IReference theRef) throws XMLStreamException { String reference = determineReferenceText(theRef); if (StringUtils.isNotBlank(reference)) { @@ -651,11 +689,10 @@ public class XmlParser extends BaseParser implements IParser { } } - private void encodeResourceToStreamWriterInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, - BaseRuntimeElementCompositeDefinition resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException { + private void encodeResourceToStreamWriterInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException { /* - * DSTU2 requires extensions to come in a specific spot within the encoded content - This is a bit of a messy way to make that happen, but hopefully this won't matter as much once we use the - * HL7 structures + * DSTU2 requires extensions to come in a specific spot within the encoded content - This is a bit of a messy + * way to make that happen, but hopefully this won't matter as much once we use the HL7 structures */ List preExtensionChildren = new ArrayList(); @@ -708,14 +745,14 @@ public class XmlParser extends BaseParser implements IParser { if (theResource instanceof IResource) { // HAPI structs IResource iResource = (IResource) theResource; - if (StringUtils.isNotBlank(iResource.getId().getValue())) { + if (StringUtils.isNotBlank(iResource.getId().getIdPart())) { resourceId = iResource.getId().getIdPart(); } } else { // HL7 structs IAnyResource resource = (IAnyResource) theResource; - if (StringUtils.isNotBlank(resource.getId())) { - resourceId = resource.getId(); + if (StringUtils.isNotBlank(resource.getId().getIdPart())) { + resourceId = resource.getId().getIdPart(); } } @@ -736,8 +773,9 @@ public class XmlParser extends BaseParser implements IParser { theEventWriter.writeDefaultNamespace(FHIR_NS); if (theResource instanceof IAnyResource) { - + // HL7.org Structures + writeOptionalTagWithValue(theEventWriter, "id", theResourceId); encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource); } else { @@ -850,8 +888,7 @@ public class XmlParser extends BaseParser implements IParser { } } - private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List> theExtensions, String tagName, boolean theIncludedResource) - throws XMLStreamException, DataFormatException { + private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List> theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException { for (IBaseExtension next : theExtensions) { if (next == null) { continue; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java index 447cb3e2647..bc0e8d1b5fd 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java @@ -40,6 +40,7 @@ import org.hl7.fhir.instance.model.IBase; import org.hl7.fhir.instance.model.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseParameters; +import org.hl7.fhir.instance.model.api.IIdType; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; @@ -266,7 +267,7 @@ public class GenericClient extends BaseClient implements IGenericClient { return myLastRequest; } - protected String getPreferredId(IResource theResource, String theId) { + protected String getPreferredId(IBaseResource theResource, String theId) { if (isNotBlank(theId)) { return theId; } @@ -574,7 +575,7 @@ public class GenericClient extends BaseClient implements IGenericClient { return resp; } - protected IResource parseResourceBody(String theResourceBody) { + protected IBaseResource parseResourceBody(String theResourceBody) { EncodingEnum encoding = null; for (int i = 0; i < theResourceBody.length() && encoding == null; i++) { switch (theResourceBody.charAt(i)) { @@ -625,7 +626,7 @@ public class GenericClient extends BaseClient implements IGenericClient { private CriterionList myCriterionList; private String myId; - private IResource myResource; + private IBaseResource myResource; private String myResourceBody; private String mySearchUrl; @@ -1597,8 +1598,8 @@ public class GenericClient extends BaseClient implements IGenericClient { private class UpdateInternal extends BaseClientExecutable implements IUpdate, IUpdateTyped, IUpdateExecutable, IUpdateWithQuery, IUpdateWithQueryTyped { private CriterionList myCriterionList; - private IdDt myId; - private IResource myResource; + private IIdType myId; + private IBaseResource myResource; private String myResourceBody; private String mySearchUrl; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java index 59ff899af92..9fd7a32a297 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java @@ -26,9 +26,13 @@ import java.io.IOException; import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; -import ca.uhn.fhir.model.api.Include; import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.IBaseResource; @@ -36,6 +40,7 @@ import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; @@ -123,7 +128,8 @@ public abstract class BaseMethodBinding implements IClientResponseHandler return myParameters; } - public Set getRequestIncludesFromParams(Object[] params) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Set getRequestIncludesFromParams(Object[] params) { if (params == null || params.length == 0) return null; int index = 0; @@ -148,7 +154,7 @@ public abstract class BaseMethodBinding implements IClientResponseHandler Set includes = new HashSet(); for (Object o : (Iterable)params[index]) { if (o instanceof Include) { - includes.add((Include) o); + includes.add(o); } } return includes; @@ -215,7 +221,7 @@ public abstract class BaseMethodBinding implements IClientResponseHandler return parser; } - protected Object[] createParametersForServerRequest(Request theRequest, IResource theResource) { + protected Object[] createParametersForServerRequest(Request theRequest, IBaseResource theResource) { Object[] params = new Object[getParameters().size()]; for (int i = 0; i < getParameters().size(); i++) { IParameter param = getParameters().get(i); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java index 288095ab83a..73a1db2f730 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java @@ -37,6 +37,7 @@ import org.hl7.fhir.instance.model.IBaseResource; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TagList; @@ -143,16 +144,18 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding enumeration = theRequest.getServletRequest().getHeaders(Constants.HEADER_CATEGORY); enumeration.hasMoreElements();) { - String nextTagComplete = enumeration.nextElement(); - MethodUtil.parseTagValue(tagList, nextTagComplete); - } - if (tagList.isEmpty() == false) { - resource.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList); + if (theServer.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) { + TagList tagList = new TagList(); + for (Enumeration enumeration = theRequest.getServletRequest().getHeaders(Constants.HEADER_CATEGORY); enumeration.hasMoreElements();) { + String nextTagComplete = enumeration.nextElement(); + MethodUtil.parseTagValue(tagList, nextTagComplete); + } + if (tagList.isEmpty() == false) { + ((IResource)resource).getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList); + } } } else { resource = null; @@ -268,21 +271,21 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding wantedResourceType = requestContainsResourceType(); - IResource retVal; + IBaseResource retVal; if (wantedResourceType != null) { - retVal = (IResource) parser.parseResource(wantedResourceType, requestReader); + retVal = parser.parseResource(wantedResourceType, requestReader); } else { retVal = parser.parseResource(requestReader); } - + retVal.setId(theRequest.getId()); - + return retVal; } @@ -294,10 +297,9 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding requestContainsResourceType() { return null; @@ -307,7 +309,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding> theIfNoneExistParams) { + public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, String theResourceBody, String theId, FhirContext theContext, Map> theIfNoneExistParams) { HttpPostClientInvocation retVal = createCreateInvocation(theResource, theResourceBody, theId, theContext); retVal.setIfNoneExistParams(theIfNoneExistParams); return retVal; } - public static HttpPostClientInvocation createCreateInvocation(IResource theResource, String theResourceBody, String theId, FhirContext theContext, String theIfNoneExistUrl) { + public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, String theResourceBody, String theId, FhirContext theContext, String theIfNoneExistUrl) { HttpPostClientInvocation retVal = createCreateInvocation(theResource, theResourceBody, theId, theContext); retVal.setIfNoneExistString(theIfNoneExistUrl); return retVal; } - public static HttpPutClientInvocation createUpdateInvocation(IResource theResource, String theResourceBody, IdDt theId, FhirContext theContext) { + public static HttpPutClientInvocation createUpdateInvocation(IBaseResource theResource, String theResourceBody, IIdType theId, FhirContext theContext) { String resourceName = theContext.getResourceDefinition(theResource).getName(); StringBuilder urlBuilder = new StringBuilder(); urlBuilder.append(resourceName); @@ -194,13 +196,13 @@ public class MethodUtil { } } - addTagsToPostOrPut(theResource, retVal); + addTagsToPostOrPut(theContext, theResource, retVal); // addContentTypeHeaderBasedOnDetectedType(retVal, theResourceBody); return retVal; } - public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IResource theResource, String theResourceBody, Map> theMatchParams) { + public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IBaseResource theResource, String theResourceBody, Map> theMatchParams) { StringBuilder b = new StringBuilder(); String resourceType = theContext.getResourceDefinition(theResource).getName(); @@ -221,7 +223,6 @@ public class MethodUtil { } } - HttpPutClientInvocation retVal; if (StringUtils.isBlank(theResourceBody)) { retVal = new HttpPutClientInvocation(theContext, theResource, b.toString()); @@ -229,12 +230,12 @@ public class MethodUtil { retVal = new HttpPutClientInvocation(theContext, theResourceBody, false, b.toString()); } - addTagsToPostOrPut(theResource, retVal); + addTagsToPostOrPut(theContext, theResource, retVal); return retVal; } - public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IResource theResource, String theResourceBody, String theMatchUrl) { + public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IBaseResource theResource, String theResourceBody, String theMatchUrl) { HttpPutClientInvocation retVal; if (StringUtils.isBlank(theResourceBody)) { retVal = new HttpPutClientInvocation(theContext, theResource, theMatchUrl); @@ -242,7 +243,7 @@ public class MethodUtil { retVal = new HttpPutClientInvocation(theContext, theResourceBody, false, theMatchUrl); } - addTagsToPostOrPut(theResource, retVal); + addTagsToPostOrPut(theContext, theResource, retVal); return retVal; } @@ -250,10 +251,10 @@ public class MethodUtil { public static EncodingEnum detectEncoding(String theBody) { for (int i = 0; i < theBody.length(); i++) { switch (theBody.charAt(i)) { - case '<': - return EncodingEnum.XML; - case '{': - return EncodingEnum.JSON; + case '<': + return EncodingEnum.XML; + case '{': + return EncodingEnum.JSON; } } return EncodingEnum.XML; @@ -406,7 +407,7 @@ public class MethodUtil { param = new ConditionalParamBinder(theRestfulOperationTypeEnum); } else if (nextAnnotation instanceof OperationParam) { Operation op = theMethod.getAnnotation(Operation.class); - param = new OperationParamBinder(op.name(), (OperationParam)nextAnnotation); + param = new OperationParamBinder(op.name(), (OperationParam) nextAnnotation); } else { continue; } @@ -519,26 +520,26 @@ public class MethodUtil { public static IQueryParameterAnd parseQueryParams(RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List theParameters) { QueryParameterAndBinder binder = null; switch (theParamDef.getParamType()) { - case COMPOSITE: - throw new UnsupportedOperationException(); - case DATE: - binder = new QueryParameterAndBinder(DateAndListParam.class, Collections.>emptyList()); - break; - case NUMBER: - binder = new QueryParameterAndBinder(NumberAndListParam.class, Collections.>emptyList()); - break; - case QUANTITY: - binder = new QueryParameterAndBinder(QuantityAndListParam.class, Collections.>emptyList()); - break; - case REFERENCE: - binder = new QueryParameterAndBinder(ReferenceAndListParam.class, Collections.>emptyList()); - break; - case STRING: - binder = new QueryParameterAndBinder(StringAndListParam.class, Collections.>emptyList()); - break; - case TOKEN: - binder = new QueryParameterAndBinder(TokenAndListParam.class, Collections.>emptyList()); - break; + case COMPOSITE: + throw new UnsupportedOperationException(); + case DATE: + binder = new QueryParameterAndBinder(DateAndListParam.class, Collections.> emptyList()); + break; + case NUMBER: + binder = new QueryParameterAndBinder(NumberAndListParam.class, Collections.> emptyList()); + break; + case QUANTITY: + binder = new QueryParameterAndBinder(QuantityAndListParam.class, Collections.> emptyList()); + break; + case REFERENCE: + binder = new QueryParameterAndBinder(ReferenceAndListParam.class, Collections.> emptyList()); + break; + case STRING: + binder = new QueryParameterAndBinder(StringAndListParam.class, Collections.> emptyList()); + break; + case TOKEN: + binder = new QueryParameterAndBinder(TokenAndListParam.class, Collections.> emptyList()); + break; } return binder.parse(theUnqualifiedParamName, theParameters); @@ -657,7 +658,7 @@ public class MethodUtil { if (reader != null) { IParser parser = ct.newParser(theContext); - IResource outcome = parser.parseResource(reader); + IBaseResource outcome = parser.parseResource(reader); if (outcome instanceof BaseOperationOutcome) { retVal.setOperationOutcome((BaseOperationOutcome) outcome); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ElementUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ElementUtil.java index 1531f71d81e..aa4eb689ed8 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ElementUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ElementUtil.java @@ -23,6 +23,8 @@ package ca.uhn.fhir.util; import java.util.ArrayList; import java.util.List; +import org.hl7.fhir.instance.model.IBase; + import ca.uhn.fhir.model.api.ICompositeElement; import ca.uhn.fhir.model.api.IElement; @@ -41,7 +43,7 @@ public class ElementUtil { } } else if (next instanceof String && (!((String)next).isEmpty())) { return false; - } else if (next != null && !((IElement) next).isEmpty()) { + } else if (next != null && !((IBase) next).isEmpty()) { return false; } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java index 823266bc205..f3d5a40984c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.util; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.TreeSet; @@ -29,6 +30,7 @@ import java.util.TreeSet; import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.IBase; import org.hl7.fhir.instance.model.IBaseResource; +import org.hl7.fhir.instance.model.api.IReference; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; @@ -39,7 +41,6 @@ import ca.uhn.fhir.context.RuntimeChildChoiceDefinition; import ca.uhn.fhir.context.RuntimeChildDirectResource; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.model.api.ExtensionDt; -import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; import ca.uhn.fhir.model.base.composite.BaseContainedDt; @@ -56,8 +57,7 @@ public class FhirTerser { myContext = theContext; } - private void addUndeclaredExtensions(IBase theElement, BaseRuntimeElementDefinition theDefinition, BaseRuntimeChildDefinition theChildDefinition, - IModelVisitor theCallback) { + private void addUndeclaredExtensions(IBase theElement, BaseRuntimeElementDefinition theDefinition, BaseRuntimeChildDefinition theChildDefinition, IModelVisitor theCallback) { if (theElement instanceof ISupportsUndeclaredExtensions) { ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement; for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) { @@ -68,14 +68,17 @@ public class FhirTerser { } /** - * Returns a list containing all child elements (including the resource itself) which are non-empty and are either of the exact type specified, or are a subclass of that type. + * Returns a list containing all child elements (including the resource itself) which are non-empty and are + * either of the exact type specified, or are a subclass of that type. *

- * For example, specifying a type of {@link StringDt} would return all non-empty string instances within the message. Specifying a type of {@link IResource} would return the resource itself, as - * well as any contained resources. + * For example, specifying a type of {@link StringDt} would return all non-empty string instances within the + * message. Specifying a type of {@link IResource} would return the resource itself, as well as any contained + * resources. *

*

- * Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not descend into linked resources (e.g. - * {@link BaseResourceReferenceDt#getResource()}) or embedded resources (e.g. Bundle.entry.resource) + * Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, + * but will not descend into linked resources (e.g. {@link BaseResourceReferenceDt#getResource()}) or embedded + * resources (e.g. Bundle.entry.resource) *

* * @param theResource @@ -102,8 +105,7 @@ public class FhirTerser { @SuppressWarnings("unchecked") @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, - ExtensionDt theNextExt) { + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { if (theType.isAssignableFrom(theNextExt.getClass())) { retVal.add((T) theNextExt); } @@ -115,39 +117,39 @@ public class FhirTerser { return retVal; } - public List getAllResourceReferences(final IBaseResource theResource) { - final ArrayList retVal = new ArrayList(); - BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, new IModelVisitor() { - @SuppressWarnings("unchecked") - @Override - public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { - if (theElement == null || theElement.isEmpty()) { - return; - } - String name = null; - if (theChildDefinition != null) { - name = theChildDefinition.getElementName(); - } - if (BaseResourceReferenceDt.class.isAssignableFrom(theElement.getClass())) { - retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt)theElement)); - } - } + public List getAllResourceReferences(final IBaseResource theResource) { + final ArrayList retVal = new ArrayList(); + BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); + visit(theResource, null, def, new IModelVisitor() { + @Override + public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + if (theElement == null || theElement.isEmpty()) { + return; + } + String name = null; + if (theChildDefinition != null) { + name = theChildDefinition.getElementName(); + } + if (BaseResourceReferenceDt.class.isAssignableFrom(theElement.getClass())) { + retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt) theElement)); + } + } - @SuppressWarnings("unchecked") - @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, - ExtensionDt theNextExt) { - String name = null; - if (theChildDefinition != null) { - name = theChildDefinition.getElementName(); - } - if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) { - retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt)theNextExt.getValue())); - } - } - }); - return retVal; } private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition theCurrentDef, List theSubList) { + @Override + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { + String name = null; + if (theChildDefinition != null) { + name = theChildDefinition.getElementName(); + } + if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) { + retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt) theNextExt.getValue())); + } + } + }); + return retVal; + } + + private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition theCurrentDef, List theSubList) { BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0)); if (theSubList.size() == 1) { @@ -229,17 +231,16 @@ public class FhirTerser { // } switch (theDefinition.getChildType()) { -// case RESOURCE: -// // Don't descend into embedded resources -// break; + case ID_DATATYPE: + case PRIMITIVE_XHTML_HL7ORG: case PRIMITIVE_XHTML: case PRIMITIVE_DATATYPE: // These are primitive types break; case RESOURCE_REF: - BaseResourceReferenceDt resRefDt = (BaseResourceReferenceDt) theElement; + IReference resRefDt = (IReference) theElement; if (resRefDt.getReference().getValue() == null && resRefDt.getResource() != null) { - IResource theResource = resRefDt.getResource(); + IBaseResource theResource = resRefDt.getResource(); if (theResource.getId() == null || theResource.getId().isEmpty() || theResource.getId().isLocal()) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); visit(theResource, null, def, theCallback); @@ -248,7 +249,7 @@ public class FhirTerser { break; case RESOURCE: case RESOURCE_BLOCK: - case COMPOSITE_DATATYPE: { + case COMPOSITE_DATATYPE: { BaseRuntimeElementCompositeDefinition childDef = (BaseRuntimeElementCompositeDefinition) theDefinition; for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) { List values = nextChild.getAccessor().getValues(theElement); @@ -281,7 +282,7 @@ public class FhirTerser { } throw new DataFormatException(b.toString()); } - + if (nextChild instanceof RuntimeChildDirectResource) { // Don't descend into embedded resources theCallback.acceptElement(nextValue, nextChild, childElementDef); @@ -305,16 +306,147 @@ public class FhirTerser { case UNDECL_EXT: { throw new IllegalStateException("state should not happen: " + theDefinition.getChildType()); } + case CONTAINED_RESOURCE_LIST: + if (theElement != null) { + BaseRuntimeElementDefinition def = myContext.getElementDefinition(theElement.getClass()); + visit(theElement, null, def, theCallback); + } + break; } } + private void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, IModelVisitor2 theCallback, List theContainingElementPath, List theChildDefinitionPath, + List> theElementDefinitionPath) { + if (theChildDefinition != null) { + theChildDefinitionPath.add(theChildDefinition); + } + theContainingElementPath.add(theElement); + theElementDefinitionPath.add(theDefinition); + + theCallback.acceptElement(theElement, Collections.unmodifiableList(theContainingElementPath), Collections.unmodifiableList(theChildDefinitionPath), Collections.unmodifiableList(theElementDefinitionPath)); + + /* + * Visit undeclared extensions + */ + if (theElement instanceof ISupportsUndeclaredExtensions) { + ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement; + for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) { + theContainingElementPath.add(nextExt); + theCallback.acceptUndeclaredExtension(nextExt, theContainingElementPath, theChildDefinitionPath, theElementDefinitionPath); + theContainingElementPath.remove(theContainingElementPath.size() - 1); + } + } + + /* + * Now visit the children of the given element + */ + switch (theDefinition.getChildType()) { + case ID_DATATYPE: + case PRIMITIVE_XHTML_HL7ORG: + case PRIMITIVE_XHTML: + case PRIMITIVE_DATATYPE: + // These are primitive types, so we don't need to visit their children + break; + case RESOURCE_REF: + IReference resRefDt = (IReference) theElement; + if (resRefDt.getReference().getValue() == null && resRefDt.getResource() != null) { + IBaseResource theResource = resRefDt.getResource(); + if (theResource.getId() == null || theResource.getId().isEmpty() || theResource.getId().isLocal()) { + BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); + visit(theResource, null, def, theCallback, theContainingElementPath, theChildDefinitionPath, theElementDefinitionPath); + } + } + break; + case RESOURCE: + case RESOURCE_BLOCK: + case COMPOSITE_DATATYPE: { + BaseRuntimeElementCompositeDefinition childDef = (BaseRuntimeElementCompositeDefinition) theDefinition; + for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) { + List values = nextChild.getAccessor().getValues(theElement); + if (values != null) { + for (IBase nextValue : values) { + if (nextValue == null) { + continue; + } + if (nextValue.isEmpty()) { + continue; + } + BaseRuntimeElementDefinition childElementDef; + childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass()); + + if (childElementDef == null) { + StringBuilder b = new StringBuilder(); + b.append("Found value of type["); + b.append(nextValue.getClass().getSimpleName()); + b.append("] which is not valid for field["); + b.append(nextChild.getElementName()); + b.append("] in "); + b.append(childDef.getName()); + b.append(" - Valid types: "); + for (Iterator iter = new TreeSet(nextChild.getValidChildNames()).iterator(); iter.hasNext();) { + BaseRuntimeElementDefinition childByName = nextChild.getChildByName(iter.next()); + b.append(childByName.getImplementingClass().getSimpleName()); + if (iter.hasNext()) { + b.append(", "); + } + } + throw new DataFormatException(b.toString()); + } + + if (nextChild instanceof RuntimeChildDirectResource) { + // Don't descend into embedded resources + theContainingElementPath.add(nextValue); + theChildDefinitionPath.add(nextChild); + theElementDefinitionPath.add(myContext.getElementDefinition(nextValue.getClass())); + theCallback.acceptElement(nextValue, Collections.unmodifiableList(theContainingElementPath), Collections.unmodifiableList(theChildDefinitionPath), Collections.unmodifiableList(theElementDefinitionPath)); + theChildDefinitionPath.remove(theChildDefinitionPath.size() - 1); + theContainingElementPath.remove(theContainingElementPath.size() - 1); + theElementDefinitionPath.remove(theElementDefinitionPath.size() - 1); + } else { + visit(nextValue, nextChild, childElementDef, theCallback, theContainingElementPath, theChildDefinitionPath, theElementDefinitionPath); + } + } + } + } + break; + } + case CONTAINED_RESOURCES: { + BaseContainedDt value = (BaseContainedDt) theElement; + for (IResource next : value.getContainedResources()) { + BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(next); + visit(next, null, def, theCallback, theContainingElementPath, theChildDefinitionPath, theElementDefinitionPath); + } + break; + } + case EXTENSION_DECLARED: + case UNDECL_EXT: { + throw new IllegalStateException("state should not happen: " + theDefinition.getChildType()); + } + case CONTAINED_RESOURCE_LIST: { + if (theElement != null) { + BaseRuntimeElementDefinition def = myContext.getElementDefinition(theElement.getClass()); + visit(theElement, null, def, theCallback, theContainingElementPath, theChildDefinitionPath, theElementDefinitionPath); + } + break; + } + } + + if (theChildDefinition != null) { + theChildDefinitionPath.remove(theChildDefinitionPath.size() - 1); + } + theContainingElementPath.remove(theContainingElementPath.size() - 1); + theElementDefinitionPath.remove(theElementDefinitionPath.size() - 1); + } + /** * Visit all elements in a given resource * *

- * Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not descend into linked resources (e.g. - * {@link BaseResourceReferenceDt#getResource()}) or embedded resources (e.g. Bundle.entry.resource) + * Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, + * but will not descend into linked resources (e.g. {@link BaseResourceReferenceDt#getResource()}) or embedded + * resources (e.g. Bundle.entry.resource) *

+ * * @param theResource * The resource to visit * @param theVisitor @@ -325,15 +457,36 @@ public class FhirTerser { visit(theResource, null, def, theVisitor); } + /** + * Visit all elements in a given resource + * + * THIS ALTERNATE METHOD IS STILL EXPERIMENTAL + * + *

+ * Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, + * but will not descend into linked resources (e.g. {@link BaseResourceReferenceDt#getResource()}) or embedded + * resources (e.g. Bundle.entry.resource) + *

+ * + * @param theResource + * The resource to visit + * @param theVisitor + * The visitor + */ + void visit(IBaseResource theResource, IModelVisitor2 theVisitor) { + BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); + visit(theResource, null, def, theVisitor, new ArrayList(), new ArrayList(), new ArrayList>()); + } + public Object getSingleValueOrNull(IBase theTarget, String thePath) { Validate.notNull(theTarget, "theTarget must not be null"); Validate.notBlank(thePath, "thePath must not be empty"); - + BaseRuntimeElementDefinition def = myContext.getElementDefinition(theTarget.getClass()); if (!(def instanceof BaseRuntimeElementCompositeDefinition)) { throw new IllegalArgumentException("Target is not a composite type: " + theTarget.getClass().getName()); } - + BaseRuntimeElementCompositeDefinition currentDef = (BaseRuntimeElementCompositeDefinition) def; Object currentObj = theTarget; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor2.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor2.java new file mode 100644 index 00000000000..ccfdbb8f712 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor2.java @@ -0,0 +1,49 @@ +package ca.uhn.fhir.util; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2015 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.List; + +import org.hl7.fhir.instance.model.IBase; +import org.hl7.fhir.instance.model.IBaseResource; +import org.hl7.fhir.instance.model.api.IBaseExtension; + +import ca.uhn.fhir.context.BaseRuntimeChildDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition; + +/** + * @see FhirTerser#visit(IBaseResource, IModelVisitor2) + */ +public interface IModelVisitor2 { + + /** + * @param theElement The element being visited + * @param theContainingElementPath The elements in the path leading up to the actual element being accepted. The first element in this path will be the outer resource being visited, and the last element will be the saem object as the object passed as theElement + */ + boolean acceptElement(IBase theElement, List theContainingElementPath, List theChildDefinitionPath, List> theElementDefinitionPath); + + /** + */ + boolean acceptUndeclaredExtension(IBaseExtension theNextExt, List theContainingElementPath, List theChildDefinitionPath, List> theElementDefinitionPath); + + + +} diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/IBaseResource.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/IBaseResource.java index 2d9ffaf41cf..e0cad744a75 100644 --- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/IBaseResource.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/IBaseResource.java @@ -1,5 +1,7 @@ package org.hl7.fhir.instance.model; +import org.hl7.fhir.instance.model.api.IIdType; + /* * #%L * HAPI FHIR - Core Library @@ -29,5 +31,11 @@ package org.hl7.fhir.instance.model; * ca.uhn.fhir.model.dstu.resource.Patient) */ public interface IBaseResource extends IBase { - // nothing here yet + + IIdType getId(); + + IBaseResource setId(String theId); + + IBaseResource setId(IIdType theId); + } diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IAnyResource.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IAnyResource.java index 764bec73488..4c6db01650f 100644 --- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IAnyResource.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IAnyResource.java @@ -24,7 +24,7 @@ import org.hl7.fhir.instance.model.IBaseResource; public interface IAnyResource extends IBaseResource { - String getId(); + IIdType getId(); IAnyResource setId(String theId); diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/IBaseResource.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseEnumeration.java similarity index 58% rename from hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/IBaseResource.java rename to hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseEnumeration.java index 94e35caef73..217be78bf98 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/IBaseResource.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseEnumeration.java @@ -1,4 +1,6 @@ -package org.hl7.fhir.instance.model; +package org.hl7.fhir.instance.model.api; + +import org.hl7.fhir.instance.model.IPrimitiveType; /* * #%L @@ -20,16 +22,8 @@ package org.hl7.fhir.instance.model; * #L% */ -/** - * For now, this is a simple marker interface indicating that a class is a resource type. - * There are two concrete types of implementations of this interrface. The first are - * HL7.org's Resource structures (e.g. - * org.hl7.fhir.instance.model.Patient) and - * the second are HAPI's Resource structures, e.g. - * ca.uhn.fhir.model.dstu.resource.Patient) - */ -public interface IBaseResource extends IBase { +public interface IBaseEnumeration> extends IPrimitiveType { - IIdType + // Marker interface } diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseXhtml.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseXhtml.java new file mode 100644 index 00000000000..0b113db2c68 --- /dev/null +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IBaseXhtml.java @@ -0,0 +1,7 @@ +package org.hl7.fhir.instance.model.api; + +import org.hl7.fhir.instance.model.IPrimitiveType; + +public interface IBaseXhtml extends IPrimitiveType { + +} diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java index 6e704aea7b3..649d9d2437c 100644 --- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java @@ -25,4 +25,34 @@ public interface IIdType { boolean isEmpty(); + boolean isLocal(); + + /** + * Returns the value of this ID. Note that this value may be a fully qualified URL, a relative/partial URL, or a simple ID. Use {@link #getIdPart()} to get just the ID portion. + * + * @see #getIdPart() + */ + String getValue(); + + /** + * Returns only the logical ID part of this ID. For example, given the ID + * "http://example,.com/fhir/Patient/123/_history/456", this method would + * return "123". + */ + String getIdPart(); + + boolean hasIdPart(); + + String getBaseUrl(); + + IIdType toUnqualifiedVersionless(); + + IIdType toVersionless(); + + IIdType setValue(String theString); + + boolean hasVersionIdPart(); + + String getVersionIdPart(); + } diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/INarrative.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/INarrative.java index ea3fab02975..554235319ea 100644 --- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/INarrative.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/INarrative.java @@ -26,4 +26,10 @@ public interface INarrative extends ICompositeType { boolean isEmpty(); + // TODO: use less broad exception type here + public void setDivAsString(String theString) throws Exception; + + // TODO: use less broad exception type here + public String getDivAsString() throws Exception; + } diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IReference.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IReference.java index 0926349fe02..8ce216dcfd3 100644 --- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IReference.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IReference.java @@ -21,16 +21,20 @@ package org.hl7.fhir.instance.model.api; */ import org.hl7.fhir.instance.model.IBase; +import org.hl7.fhir.instance.model.IBaseResource; +import org.hl7.fhir.instance.model.IPrimitiveType; public interface IReference extends IBase { - IAnyResource getResource(); + IBaseResource getResource(); - void setResource(IAnyResource theResource); + void setResource(IBaseResource theResource); - String getReference(); + IIdType getReference(); IReference setReference(String theReference); IBase setDisplay(String theValue); + + IPrimitiveType getDisplayElement(); } diff --git a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java index da7969555f6..54aa208ed0d 100644 --- a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java +++ b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java @@ -122,12 +122,13 @@ public abstract class BaseResource extends BaseElement implements IResource { myId = theId; } - public void setId(String theId) { + public BaseResource setId(String theId) { if (theId == null) { myId = null; } else { myId = new IdDt(theId); } + return this; } @Override diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java index b15707f5f15..831215fd597 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java @@ -5,11 +5,15 @@ import static org.junit.Assert.*; import java.io.StringReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.UUID; import org.apache.commons.io.IOUtils; import org.custommonkey.xmlunit.Diff; import org.custommonkey.xmlunit.XMLUnit; +import org.hamcrest.text.StringContainsInOrder; +import org.hl7.fhir.instance.model.IBaseResource; import org.junit.BeforeClass; import org.junit.Test; @@ -26,6 +30,7 @@ import ca.uhn.fhir.model.dstu2.composite.CodingDt; import ca.uhn.fhir.model.dstu2.composite.ContainedDt; import ca.uhn.fhir.model.dstu2.composite.DurationDt; import ca.uhn.fhir.model.dstu2.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu2.composite.IdentifierDt; import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu2.resource.AllergyIntolerance; import ca.uhn.fhir.model.dstu2.resource.Binary; @@ -36,6 +41,7 @@ import ca.uhn.fhir.model.dstu2.resource.MedicationPrescription; import ca.uhn.fhir.model.dstu2.resource.Observation; import ca.uhn.fhir.model.dstu2.resource.Organization; import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.dstu2.valueset.DocumentReferenceStatusEnum; import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum; import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.DateTimeDt; @@ -54,6 +60,204 @@ public class XmlParserDstu2Test { XMLUnit.setIgnoreWhitespace(true); } + @Test + public void testEncodeBinaryWithNoContentType() { + Binary b = new Binary(); + b.setContent(new byte[] {1,2,3,4}); + + String output = ourCtx.newXmlParser().encodeResourceToString(b); + ourLog.info(output); + + assertEquals("", output); + } + + + @Test + public void testEncodeNonContained() { + // Create an organization + Organization org = new Organization(); + org.setId("Organization/65546"); + org.getNameElement().setValue("Contained Test Organization"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); + patient.getManagingOrganization().setResource(org); + + // Create a list containing both resources. In a server method, you might just + // return this list, but here we will create a bundle to encode. + List resources = new ArrayList(); + resources.add(org); + resources.add(patient); + + // Create a bundle with both + ca.uhn.fhir.model.dstu2.resource.Bundle b = new ca.uhn.fhir.model.dstu2.resource.Bundle(); + b.addEntry().setResource(org); + b.addEntry().setResource(patient); + + // Encode the buntdle + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b); + ourLog.info(encoded); + assertThat(encoded, not(containsString(""))); + assertThat(encoded, stringContainsInOrder("", "")); + assertThat(encoded, containsString("")); + assertThat(encoded, stringContainsInOrder("", "")); + + encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, not(containsString(""))); + assertThat(encoded, containsString("")); + + + } + + @Test + public void testParseNarrative() throws Exception { + //@formatter:off + String htmlNoNs = "
AAABBBCCC
"; + String htmlNs = htmlNoNs.replace("
", "
"); + String res= "\n" + + " \n" + + " \n" + + " " + htmlNs + "\n" + + " \n" + + ""; + //@formatter:on + + Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res); + assertEquals(htmlNoNs, p.getText().getDiv().getValueAsString()); + } + + /** + * Thanks to Alexander Kley! + */ + @Test + public void testParseContainedBinaryResource() { + byte[] bin = new byte[] { 0, 1, 2, 3, 4 }; + final Binary binary = new Binary(); + binary.setContentType("PatientConsent").setContent(bin); + // binary.setId(UUID.randomUUID().toString()); + + ca.uhn.fhir.model.dstu2.resource.DocumentManifest manifest = new ca.uhn.fhir.model.dstu2.resource.DocumentManifest(); + // manifest.setId(UUID.randomUUID().toString()); + CodeableConceptDt cc = new CodeableConceptDt(); + cc.addCoding().setSystem("mySystem").setCode("PatientDocument"); + manifest.setType(cc); + manifest.setMasterIdentifier(new IdentifierDt().setSystem("mySystem").setValue(UUID.randomUUID().toString())); + manifest.addContent().setP(new ResourceReferenceDt(binary)); + manifest.setStatus(DocumentReferenceStatusEnum.CURRENT); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(manifest); + ourLog.info(encoded); + assertThat(encoded, StringContainsInOrder.stringContainsInOrder(Arrays.asList("contained>", ""))); + + ca.uhn.fhir.model.dstu2.resource.DocumentManifest actual = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.DocumentManifest.class, encoded); + assertEquals(1, actual.getContained().getContainedResources().size()); + assertEquals(1, actual.getContent().size()); + assertNotNull(((ResourceReferenceDt)actual.getContent().get(0).getP()).getResource()); + + } + + @Test + public void testEncodeAndParseContained() { + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + + // Create an organization, note that the organization does not have an ID + Organization org = new Organization(); + org.getNameElement().setValue("Contained Test Organization"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); + + // Put the organization as a reference in the patient resource + patient.getManagingOrganization().setResource(org); + + String encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, containsString("")); + assertThat(encoded, containsString("")); + + // Create a bundle with just the patient resource + ca.uhn.fhir.model.dstu2.resource.Bundle b = new ca.uhn.fhir.model.dstu2.resource.Bundle(); + b.addEntry().setResource(patient); + + // Encode the bundle + encoded = xmlParser.encodeResourceToString(b); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); + assertThat(encoded, containsString("")); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "", "")))); + + // Re-parse the bundle + patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient)); + assertEquals("#1", patient.getManagingOrganization().getReference().getValue()); + + assertNotNull(patient.getManagingOrganization().getResource()); + org = (Organization) patient.getManagingOrganization().getResource(); + assertEquals("#1", org.getId().getValue()); + assertEquals("Contained Test Organization", org.getName()); + + // And re-encode a second time + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + assertThat(encoded, containsString("")); + + // And re-encode once more, with the references cleared + patient.getContained().getContainedResources().clear(); + patient.getManagingOrganization().setReference((String)null); + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + assertThat(encoded, containsString("")); + + // And re-encode once more, with the references cleared and a manually set local ID + patient.getContained().getContainedResources().clear(); + patient.getManagingOrganization().setReference((String)null); + patient.getManagingOrganization().getResource().setId(("#333")); + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + + } + + + @Test + public void testEncodeContainedWithNarrativeIsSuppresed() throws Exception { + IParser parser = ourCtx.newXmlParser().setPrettyPrint(true); + + // Create an organization, note that the organization does not have an ID + Organization org = new Organization(); + org.getNameElement().setValue("Contained Test Organization"); + org.getText().setDiv("
FOOBAR
"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); + patient.getText().setDiv("
BARFOO
"); + patient.getManagingOrganization().setResource(org); + + String encoded = parser.encodeResourceToString(patient); + ourLog.info(encoded); + + assertThat(encoded, stringContainsInOrder("", "
BARFOO
", "", "", "", " strings = t.getAllPopulatedChildElementsOfType(b, StringDt.class); + + assertEquals(1, strings.size()); + assertThat(strings, containsInAnyOrder(new StringDt("BUNDLE"))); + + } + + @Test + public void testGetAllPopulatedChildElementsOfTypeDescendsIntoContained() { + Patient p = new Patient(); + p.addName().addFamily("PATIENT"); + + Organization o = new Organization(); + o.getNameElement().setValue("ORGANIZATION"); + p.getContained().getContainedResources().add(o); + + FhirTerser t = ourCtx.newTerser(); + List strings = t.getAllPopulatedChildElementsOfType(p, StringDt.class); + + assertEquals(2, strings.size()); + assertThat(strings, containsInAnyOrder(new StringDt("PATIENT"), new StringDt("ORGANIZATION"))); + + } + + @Test + public void testVisitWithModelVisitor2() { + IModelVisitor2 visitor = mock(IModelVisitor2.class); + + ArgumentCaptor element = ArgumentCaptor.forClass(IBase.class); + ArgumentCaptor> containingElementPath = ArgumentCaptor.forClass(getListClass(IBase.class)); + ArgumentCaptor> childDefinitionPath = ArgumentCaptor.forClass(getListClass(BaseRuntimeChildDefinition.class)); + ArgumentCaptor>> elementDefinitionPath = ArgumentCaptor.forClass(getListClass2()); + when(visitor.acceptElement(element.capture(), containingElementPath.capture(), childDefinitionPath.capture(), elementDefinitionPath.capture())).thenReturn(true); + + Patient p = new Patient(); + p.addLink().getTypeElement().setValue("CODE"); + ourCtx.newTerser().visit(p, visitor); + + assertEquals(3, element.getAllValues().size()); + assertSame(p, element.getAllValues().get(0)); + assertSame(p.getLinkFirstRep(), element.getAllValues().get(1)); + assertSame(p.getLinkFirstRep().getTypeElement(), element.getAllValues().get(2)); + + assertEquals(3, containingElementPath.getAllValues().size()); +// assertEquals(0, containingElementPath.getAllValues().get(0).size()); +// assertEquals(1, containingElementPath.getAllValues().get(1).size()); +// assertEquals(2, containingElementPath.getAllValues().get(2).size()); + + } + + /** + * See + * http://stackoverflow.com/questions/182636/how-to-determine-the-class-of-a-generic-type + */ + private static Class> getListClass(Class theClass) { + return new ClassGetter>() {}.get(); + } + + /** + * See + * http://stackoverflow.com/questions/182636/how-to-determine-the-class-of-a-generic-type + */ + private static Class>> getListClass2() { + return new ClassGetter>>() {}.get(); + } + + /** + * See + * http://stackoverflow.com/questions/182636/how-to-determine-the-class-of-a-generic-type + */ + private static abstract class ClassGetter { + @SuppressWarnings("unchecked") + public final Class get() { + final ParameterizedType superclass = (ParameterizedType) + getClass().getGenericSuperclass(); + Type type = superclass.getActualTypeArguments()[0]; + if (type instanceof ParameterizedType) { + return (Class) ((ParameterizedType) type).getOwnerType(); + } + return (Class)type; + } + } + +} diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/util/FhirTerserTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/util/FhirTerserTest.java deleted file mode 100644 index d15bc047614..00000000000 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/util/FhirTerserTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package ca.uhn.fhir.util; - -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import java.util.List; - -import org.junit.Test; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.dstu2.resource.Bundle; -import ca.uhn.fhir.model.dstu2.resource.Organization; -import ca.uhn.fhir.model.dstu2.resource.Patient; -import ca.uhn.fhir.model.primitive.StringDt; - -public class FhirTerserTest { - - private static FhirContext ourCtx = new FhirContext(); - - @Test - public void testGetAllPopulatedChildElementsOfTypeDoesntDescendIntoEmbedded() { - Patient p = new Patient(); - p.addName().addFamily("PATIENT"); - - Bundle b = new Bundle(); - b.addEntry().setResource(p); - b.addLink().setRelation("BUNDLE"); - - FhirTerser t = ourCtx.newTerser(); - List strings = t.getAllPopulatedChildElementsOfType(b, StringDt.class); - - assertEquals(1, strings.size()); - assertThat(strings, containsInAnyOrder(new StringDt("BUNDLE"))); - - } - - @Test - public void testGetAllPopulatedChildElementsOfTypeDescendsIntoContained() { - Patient p = new Patient(); - p.addName().addFamily("PATIENT"); - - Organization o = new Organization(); - o.getNameElement().setValue("ORGANIZATION"); - p.getContained().getContainedResources().add(o); - - FhirTerser t = ourCtx.newTerser(); - List strings = t.getAllPopulatedChildElementsOfType(p, StringDt.class); - - assertEquals(2, strings.size()); - assertThat(strings, containsInAnyOrder(new StringDt("PATIENT"), new StringDt("ORGANIZATION"))); - - } - -} diff --git a/hapi-fhir-structures-hl7org-dstu2/.classpath b/hapi-fhir-structures-hl7org-dstu2/.classpath index acfe2cc4f2a..3e385a31988 100644 --- a/hapi-fhir-structures-hl7org-dstu2/.classpath +++ b/hapi-fhir-structures-hl7org-dstu2/.classpath @@ -19,11 +19,11 @@ + - diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index fdfed0215db..d531858443a 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -18,7 +18,7 @@ ca.uhn.hapi.fhir hapi-fhir-base - 0.9-SNAPSHOT + 1.0-SNAPSHOT diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java index b80cd8cf9fc..90e1051277c 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/DomainResource.java @@ -40,11 +40,12 @@ import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.annotations.Description; import org.hl7.fhir.instance.model.api.IBaseHasExtensions; import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; +import org.hl7.fhir.instance.model.api.IDomainResource; /** * A resource that includes narrative, extensions, and contained resources. */ @ResourceDef(name="DomainResource", profile="http://hl7.org/fhir/Profile/DomainResource") -public abstract class DomainResource extends Resource implements IBaseHasExtensions, IBaseHasModifierExtensions { +public abstract class DomainResource extends Resource implements IBaseHasExtensions, IBaseHasModifierExtensions, IDomainResource { /** * A human-readable narrative that contains a summary of the resource, and may be used to represent the content of the resource to a human. The narrative need not encode all the structured data, but is required to contain sufficient detail to make it "clinically safe" for a human to just read the narrative. Resource definitions may define what content should be represented in the narrative to ensure clinical safety. diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java index c0ed0894587..351a4c53d36 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Enumeration.java @@ -2,6 +2,7 @@ package org.hl7.fhir.instance.model; import org.hl7.fhir.instance.model.annotations.DatatypeDef; import org.hl7.fhir.instance.model.api.IBaseEnumFactory; +import org.hl7.fhir.instance.model.api.IBaseEnumeration; /* Copyright (c) 2011+, HL7, Inc @@ -37,7 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. * */ @DatatypeDef(name="enumeration") -public class Enumeration> extends PrimitiveType { +public class Enumeration> extends PrimitiveType implements IBaseEnumeration { private static final long serialVersionUID = 1L; private EnumFactory myEnumFactory; diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/IdType.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/IdType.java index c91952854ba..78663154302 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/IdType.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/IdType.java @@ -28,8 +28,7 @@ POSSIBILITY OF SUCH DAMAGE. */ package org.hl7.fhir.instance.model; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.math.BigDecimal; @@ -38,13 +37,9 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.hl7.fhir.instance.model.annotations.DatatypeDef; -import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IIdType; -import ca.uhn.fhir.model.api.IPrimitiveDatatype; -import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.annotation.SimpleSetter; -import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.server.Constants; @@ -545,37 +540,12 @@ public class IdType extends UriType implements IIdType { return isBlank(getValue()); } - public void applyTo(IBaseResource theResouce) { - if (theResouce == null) { - throw new NullPointerException("theResource can not be null"); - } else if (theResouce instanceof IResource) { - ((IResource) theResouce).setId(new IdType(getValue())); - } else if (theResouce instanceof IAnyResource) { - ((IAnyResource) theResouce).setId(getIdPart()); - } else { - throw new IllegalArgumentException("Unknown resource class type, does not implement IResource or extend Resource"); - } - } - - /** - * Retrieves the ID from the given resource instance - */ - public static IdType of(IBaseResource theResouce) { - if (theResouce == null) { - throw new NullPointerException("theResource can not be null"); - } else if (theResouce instanceof IResource) { - return ((IBaseResource) theResouce).getIdElement(); - } else if (theResouce instanceof IAnyResource) { - // TODO: implement - throw new UnsupportedOperationException(); - } else { - throw new IllegalArgumentException("Unknown resource class type, does not implement IResource or extend Resource"); - } - } - @Override public IdType copy() { return new IdType(getValue()); } -} + + + +} \ No newline at end of file diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Narrative.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Narrative.java index 3babedb4c29..430e1a0d98b 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Narrative.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Narrative.java @@ -31,17 +31,16 @@ package org.hl7.fhir.instance.model; // Generated on Wed, Feb 18, 2015 12:09-0500 for FHIR v0.4.0 -import java.util.*; +import java.util.List; import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.instance.model.annotations.Child; +import org.hl7.fhir.instance.model.annotations.DatatypeDef; +import org.hl7.fhir.instance.model.annotations.Description; +import org.hl7.fhir.instance.model.api.INarrative; import org.hl7.fhir.utilities.xhtml.XhtmlComposer; import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlParser; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.instance.model.annotations.Child; -import org.hl7.fhir.instance.model.annotations.Description; -import org.hl7.fhir.instance.model.annotations.DatatypeDef; -import org.hl7.fhir.instance.model.api.INarrative; /** * A human-readable formatted text, including images. */ @@ -158,8 +157,8 @@ public class Narrative extends Element implements INarrative { /** * The actual narrative content, a stripped down version of XHTML. */ -// @Child(name="div", type={}, order=1, min=1, max=1) -// @Description(shortDefinition="Limited xhtml content", formalDefinition="The actual narrative content, a stripped down version of XHTML." ) + @Child(name="div", type={}, order=1, min=1, max=1) + @Description(shortDefinition="Limited xhtml content", formalDefinition="The actual narrative content, a stripped down version of XHTML." ) protected XhtmlNode div; private static final long serialVersionUID = 1463852859L; diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Patient.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Patient.java index 3c9594264b0..8b394fc74e0 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Patient.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Patient.java @@ -31,14 +31,15 @@ package org.hl7.fhir.instance.model; // Generated on Wed, Feb 18, 2015 12:09-0500 for FHIR v0.4.0 -import java.util.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.instance.model.annotations.ResourceDef; -import org.hl7.fhir.instance.model.annotations.SearchParamDefinition; import org.hl7.fhir.instance.model.annotations.Block; import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.annotations.Description; +import org.hl7.fhir.instance.model.annotations.ResourceDef; +import org.hl7.fhir.instance.model.annotations.SearchParamDefinition; /** * Demographics and other administrative information about a person or animal receiving care or other health-related services. */ diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Reference.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Reference.java index 64b9fa2083a..c62141905e8 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Reference.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Reference.java @@ -65,7 +65,9 @@ public class Reference extends Type implements IReference, ICompositeType { * Constructor */ public Reference(StringType theReference) { - this.reference = theReference; + if (theReference != null) { + this.reference = new IdType(theReference.getValue()); + } } /** @@ -73,21 +75,21 @@ public class Reference extends Type implements IReference, ICompositeType { */ public Reference(String theReference) { if (StringUtils.isNotBlank(theReference)) { - this.reference = new StringType(theReference); + this.reference = new IdType(theReference); } } /** * This is not a part of the "wire format" resource, but can be changed/accessed by parsers */ - private transient IAnyResource resource; + private transient IBaseResource resource; /** * Retrieves the actual resource referenced by this reference. Note that the resource itself is not * a part of the FHIR "wire format" and is never transmitted or receieved inline, but this property * may be changed/accessed by parsers. */ - public IAnyResource getResource() { + public IBaseResource getResource() { return resource; } @@ -96,7 +98,7 @@ public class Reference extends Type implements IReference, ICompositeType { * a part of the FHIR "wire format" and is never transmitted or receieved inline, but this property * may be changed/accessed by parsers. */ - public void setResource(IAnyResource theResource) { + public void setResource(IBaseResource theResource) { resource = theResource; } @@ -105,7 +107,7 @@ public class Reference extends Type implements IReference, ICompositeType { */ @Child(name = "reference", type = {StringType.class}, order = 0, min = 0, max = 1) @Description(shortDefinition="Relative, internal or absolute URL reference", formalDefinition="A reference to a location at which the other resource is found. The reference may be a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources." ) - protected StringType reference; + protected IdType reference; /** * Plain text narrative that identifies the resource in addition to the resource reference. @@ -119,12 +121,12 @@ public class Reference extends Type implements IReference, ICompositeType { /** * @return {@link #reference} (A reference to a location at which the other resource is found. The reference may be a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources.). This is the underlying object with id, value and extensions. The accessor "getReference" gives direct access to the value */ - public StringType getReferenceElement() { + public IdType getReferenceElement() { if (this.reference == null) if (Configuration.errorOnAutoCreate()) throw new Error("Attempt to auto-create Reference.reference"); else if (Configuration.doAutoCreate()) - this.reference = new StringType(); // bb + this.reference = new IdType(); // bb return this.reference; } @@ -139,7 +141,7 @@ public class Reference extends Type implements IReference, ICompositeType { /** * @param value {@link #reference} (A reference to a location at which the other resource is found. The reference may be a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources.). This is the underlying object with id, value and extensions. The accessor "getReference" gives direct access to the value */ - public Reference setReferenceElement(StringType value) { + public Reference setReferenceElement(IdType value) { this.reference = value; return this; } @@ -147,8 +149,8 @@ public class Reference extends Type implements IReference, ICompositeType { /** * @return A reference to a location at which the other resource is found. The reference may be a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources. */ - public String getReference() { - return this.reference == null ? null : this.reference.getValue(); + public IdType getReference() { + return getReferenceElement(); } /** @@ -159,7 +161,7 @@ public class Reference extends Type implements IReference, ICompositeType { this.reference = null; else { if (this.reference == null) - this.reference = new StringType(); + this.reference = new IdType(); this.reference.setValue(value); } return this; @@ -253,7 +255,7 @@ public class Reference extends Type implements IReference, ICompositeType { } public boolean isEmpty() { - return super.isEmpty() && (reference == null || reference.isEmpty()) && (display == null || display.isEmpty()) + return super.isEmpty() && (reference == null || reference.isEmpty()) && (display == null || display.isEmpty()) && resource == null ; } diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Resource.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Resource.java index bcfa6fe669c..ac592f2fbcd 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Resource.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/model/Resource.java @@ -31,15 +31,14 @@ package org.hl7.fhir.instance.model; // Generated on Wed, Feb 18, 2015 12:09-0500 for FHIR v0.4.0 -import java.util.*; +import java.util.List; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.instance.model.annotations.ResourceDef; -import org.hl7.fhir.instance.model.annotations.SearchParamDefinition; -import org.hl7.fhir.instance.model.annotations.Block; import org.hl7.fhir.instance.model.annotations.Child; import org.hl7.fhir.instance.model.annotations.Description; +import org.hl7.fhir.instance.model.annotations.ResourceDef; import org.hl7.fhir.instance.model.api.IAnyResource; +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.utilities.Utilities; /** * Base Resource for everything. */ @@ -111,8 +110,8 @@ public abstract class Resource extends Base implements IAnyResource { /** * @return The logical id of the resource, as used in the url for the resoure. Once assigned, this value never changes. */ - public String getId() { - return this.id == null ? null : this.id.getValue(); + public IdType getId() { + return getIdElement(); // this.id == null ? null : this.id.getValue(); } /** @@ -129,6 +128,14 @@ public abstract class Resource extends Base implements IAnyResource { return this; } + /** + * @param value The logical id of the resource, as used in the url for the resoure. Once assigned, this value never changes. + */ + public Resource setId(IIdType value) { + this.id = (IdType) value; + return this; + } + /** * @return {@link #meta} (The metadata about the resource. This is content that is maintained by the infrastructure. Changes to the content may not always be associated with version changes to the resource.) */ diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java index 52a8e8588b0..e528b9ba835 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java @@ -33,8 +33,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -//@DatatypeDef() -public class XhtmlNode { +import org.hl7.fhir.instance.model.IPrimitiveType; +import org.hl7.fhir.instance.model.annotations.DatatypeDef; +import org.hl7.fhir.instance.model.api.IBaseXhtml; + +@DatatypeDef(name="xhtml") +public class XhtmlNode implements IBaseXhtml { public static final String NBSP = Character.toString((char)0xa0); @@ -280,7 +284,40 @@ public class XhtmlNode { return e1.equalsDeep(e2); } - public String getValueAsString() throws Exception { - return new XhtmlComposer().compose(this); + public String getValueAsString() { + try { + return new XhtmlComposer().compose(this); + } catch (Exception e) { + // TODO: composer shouldn't throw exception like this + throw new RuntimeException(e); + } + } + + @Override + public void setValueAsString(String theValue) throws IllegalArgumentException { + try { + // TODO: this is ugly + XhtmlNode fragment = new XhtmlParser().parseFragment(theValue); + this.Attributes = fragment.Attributes; + this.childNodes = fragment.childNodes; + this.content = fragment.content; + this.name = fragment.name; + this.nodeType= fragment.nodeType; + } catch (Exception e) { + // TODO: composer shouldn't throw exception like this + throw new RuntimeException(e); + } + + } + + @Override + public String getValue() { + return getValueAsString(); + } + + @Override + public IPrimitiveType setValue(String theValue) throws IllegalArgumentException { + setValueAsString(theValue); + return this; } } diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java index 85340e98add..304da0046c3 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/model/ModelInheritanceTest.java @@ -12,6 +12,7 @@ import org.hl7.fhir.instance.model.Coding; import org.hl7.fhir.instance.model.DecimalType; import org.hl7.fhir.instance.model.DomainResource; import org.hl7.fhir.instance.model.Element; +import org.hl7.fhir.instance.model.Enumeration; import org.hl7.fhir.instance.model.Extension; import org.hl7.fhir.instance.model.IBase; import org.hl7.fhir.instance.model.ICompositeType; @@ -36,16 +37,20 @@ import org.hl7.fhir.instance.model.api.IBaseBooleanDatatype; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype; +import org.hl7.fhir.instance.model.api.IBaseEnumeration; import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseHasExtensions; import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; import org.hl7.fhir.instance.model.api.IBaseIntegerDatatype; +import org.hl7.fhir.instance.model.api.IBaseXhtml; import org.hl7.fhir.instance.model.api.ICoding; import org.hl7.fhir.instance.model.api.IDatatypeElement; +import org.hl7.fhir.instance.model.api.IDomainResource; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IMetaType; import org.hl7.fhir.instance.model.api.INarrative; import org.hl7.fhir.instance.model.api.IReference; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.junit.Test; public class ModelInheritanceTest { @@ -78,6 +83,11 @@ public class ModelInheritanceTest { assertTrue(ICompositeType.class.isAssignableFrom(Address.class)); } + @Test + public void testXhtml() { + assertTrue(IBaseXhtml.class.isAssignableFrom(XhtmlNode.class)); + } + @Test public void testBackboneElement() { assertTrue(IBackboneElement.class.isAssignableFrom(BackboneElement.class)); @@ -122,6 +132,7 @@ public class ModelInheritanceTest { public void testDomainResource() { assertTrue(IBaseHasExtensions.class.isAssignableFrom(DomainResource.class)); assertTrue(IBaseHasModifierExtensions.class.isAssignableFrom(DomainResource.class)); + assertTrue(IDomainResource.class.isAssignableFrom(DomainResource.class)); } @Test @@ -129,6 +140,11 @@ public class ModelInheritanceTest { assertTrue(IBaseHasExtensions.class.isAssignableFrom(Element.class)); } + @Test + public void testEnumeration() { + assertTrue(IBaseEnumeration.class.isAssignableFrom(Enumeration.class)); + } + /** * Should be "implements IBaseExtension" */ diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java index b34a4c45c7f..361a3697619 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java @@ -77,27 +77,20 @@ public class XmlParserTest { @BeforeClass public static void beforeClass2() { - System.setProperty("file.encoding", "ISO-8859-1"); + System.setProperty("file.encoding", "ISO-8859-1"); } - - @Test - public void testProfileWithBoundCode() throws IOException { - String content = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/DMIXAuditException.xml"), "UTF-8"); - ourCtx.newXmlParser().parseResource(Profile.class, content); - } - + @Test public void testEncodeBinaryWithNoContentType() { Binary b = new Binary(); - b.setContent(new byte[] {1,2,3,4}); - + b.setContent(new byte[] { 1, 2, 3, 4 }); + String output = ourCtx.newXmlParser().encodeResourceToString(b); ourLog.info(output); - + assertEquals("", output); } - - + @Test public void testEncodeNonContained() { // Create an organization @@ -110,18 +103,18 @@ public class XmlParserTest { patient.setId("Patient/1333"); patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); patient.getManagingOrganization().setResource(org); - + // Create a list containing both resources. In a server method, you might just // return this list, but here we will create a bundle to encode. List resources = new ArrayList(); resources.add(org); - resources.add(patient); - + resources.add(patient); + // Create a bundle with both Bundle b = new Bundle(); b.addEntry().setResource(org); b.addEntry().setResource(patient); - + // Encode the buntdle String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b); ourLog.info(encoded); @@ -129,13 +122,29 @@ public class XmlParserTest { assertThat(encoded, stringContainsInOrder("", "
")); assertThat(encoded, containsString("")); assertThat(encoded, stringContainsInOrder("", "")); - + encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); ourLog.info(encoded); assertThat(encoded, not(containsString(""))); assertThat(encoded, containsString("")); + + } + + @Test + public void testParseNarrative() throws Exception { + //@formatter:off + String htmlNoNs = "
AAABBBCCC
"; + String htmlNs = htmlNoNs.replace("
", "
"); + String res= "\n" + + " \n" + + " \n" + + " " + htmlNs + "\n" + + " \n" + + ""; + //@formatter:on - + Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res); + assertEquals(htmlNoNs, p.getText().getDivAsString()); } @Test @@ -150,22 +159,25 @@ public class XmlParserTest { // Create a patient Patient patient = new Patient(); patient.setId("Patient/1333"); - patient.addIdentifier().setSystem("urn:mrns").setValue( "253345"); + patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); patient.getText().setDivAsString("
BARFOO
"); patient.getManagingOrganization().setResource(org); - + String encoded = parser.encodeResourceToString(patient); ourLog.info(encoded); + + assertThat(encoded, stringContainsInOrder("", "
BARFOO
", "", "", "", "")); assertThat(encoded, containsString("")); - + // Create a bundle with just the patient resource Bundle b = new Bundle(); b.addEntry().setResource(patient); - - // Encode the buntdle + + // Encode the bundle encoded = xmlParser.encodeResourceToString(b); ourLog.info(encoded); - assertThat(encoded, stringContainsInOrder(Arrays.asList("","id=\"1\"", ""))); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); assertThat(encoded, containsString("")); assertThat(encoded, stringContainsInOrder(Arrays.asList("", ""))); assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "", "")))); - + // Re-parse the bundle patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient)); - assertEquals("#1", patient.getManagingOrganization().getReference()); - + assertEquals("#1", patient.getManagingOrganization().getReference().getValue()); + assertNotNull(patient.getManagingOrganization().getResource()); org = (Organization) patient.getManagingOrganization().getResource(); - assertEquals("#1", org.getId()); + assertEquals("#1", org.getId().getValue()); assertEquals("Contained Test Organization", org.getName()); - + // And re-encode a second time encoded = xmlParser.encodeResourceToString(patient); ourLog.info(encoded); - assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); - assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); assertThat(encoded, containsString("")); // And re-encode once more, with the references cleared @@ -216,8 +228,8 @@ public class XmlParserTest { patient.getManagingOrganization().setReference(null); encoded = xmlParser.encodeResourceToString(patient); ourLog.info(encoded); - assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); - assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); assertThat(encoded, containsString("")); // And re-encode once more, with the references cleared and a manually set local ID @@ -226,59 +238,55 @@ public class XmlParserTest { patient.getManagingOrganization().getResource().setId(("#333")); encoded = xmlParser.encodeResourceToString(patient); ourLog.info(encoded); - assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); - assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); - + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + } - - + /** * Thanks to Alexander Kley! */ @Test public void testParseContainedBinaryResource() { - byte[] bin = new byte[] {0,1,2,3,4}; - final Binary binary = new Binary(); - binary.setContentType("PatientConsent").setContent( bin); -// binary.setId(UUID.randomUUID().toString()); - - DocumentManifest manifest = new DocumentManifest(); -// manifest.setId(UUID.randomUUID().toString()); - CodeableConcept cc = new CodeableConcept(); - cc.addCoding().setSystem("mySystem").setCode( "PatientDocument"); + byte[] bin = new byte[] { 0, 1, 2, 3, 4 }; + final Binary binary = new Binary(); + binary.setContentType("PatientConsent").setContent(bin); + // binary.setId(UUID.randomUUID().toString()); + + DocumentManifest manifest = new DocumentManifest(); + // manifest.setId(UUID.randomUUID().toString()); + CodeableConcept cc = new CodeableConcept(); + cc.addCoding().setSystem("mySystem").setCode("PatientDocument"); manifest.setType(cc); - manifest.setMasterIdentifier(new Identifier().setSystem("mySystem").setValue( UUID.randomUUID().toString())); - manifest.addContent().setResource(binary); - manifest.setStatus(DocumentReferenceStatus.CURRENT); - - String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(manifest); - ourLog.info(encoded); - assertThat(encoded, StringContainsInOrder.stringContainsInOrder(Arrays.asList("contained>",""))); - - DocumentManifest actual = ourCtx.newXmlParser().parseResource(DocumentManifest.class, encoded); - assertEquals(1, actual.getContained().size()); - assertEquals(1, actual.getContent().size()); - assertNotNull(actual.getContent().get(0).getResource()); - + manifest.setMasterIdentifier(new Identifier().setSystem("mySystem").setValue(UUID.randomUUID().toString())); + manifest.addContent().setResource(binary); + manifest.setStatus(DocumentReferenceStatus.CURRENT); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(manifest); + ourLog.info(encoded); + assertThat(encoded, StringContainsInOrder.stringContainsInOrder(Arrays.asList("contained>", ""))); + + DocumentManifest actual = ourCtx.newXmlParser().parseResource(DocumentManifest.class, encoded); + assertEquals(1, actual.getContained().size()); + assertEquals(1, actual.getContent().size()); + assertNotNull(actual.getContent().get(0).getResource()); + } - - + @Test public void testComposition() { - + Composition comp = new Composition(); comp.setId("1"); - + ourCtx.newXmlParser().encodeResourceToString(comp); ourCtx.newXmlParser().encodeResourceToString(comp); ourCtx.newXmlParser().encodeResourceToString(comp); ourCtx.newXmlParser().encodeResourceToString(comp); - -// comp. - + + // comp. + } - - @Test public void testEncodeBinaryResource() { @@ -288,7 +296,7 @@ public class XmlParserTest { patient.setContent(new byte[] { 1, 2, 3, 4 }); String val = ourCtx.newXmlParser().encodeResourceToString(patient); - assertEquals("AQIDBA==", val); + assertEquals("", val); } @@ -310,7 +318,7 @@ public class XmlParserTest { @Test public void testEncodeBundle() throws InterruptedException { Bundle b = new Bundle(); - b.getMeta().addTag().setSystem("http://hl7.org/fhir/tag").setCode( "http://hl7.org/fhir/tag/message").setDisplay("Message"); + b.getMeta().addTag().setSystem("http://hl7.org/fhir/tag").setCode("http://hl7.org/fhir/tag/message").setDisplay("Message"); InstantType pub = InstantType.withCurrentTime(); b.getMeta().setLastUpdatedElement(pub); @@ -346,7 +354,7 @@ public class XmlParserTest { Bundle b = new Bundle(); BundleEntryComponent e = b.addEntry(); e.setResource(new Patient()); - e.getResource().getMeta().addTag().setSystem("scheme").setCode( "term").setDisplay( "label"); + e.getResource().getMeta().addTag().setSystem("scheme").setCode("term").setDisplay("label"); String val = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b); ourLog.info(val); @@ -363,7 +371,6 @@ public class XmlParserTest { } - @Test public void testEncodeEscapedChars() { @@ -409,7 +416,7 @@ public class XmlParserTest { DiagnosticReport rpt = new DiagnosticReport(); Specimen spm = new Specimen(); - spm.addIdentifier().setSystem("urn").setValue( "123"); + spm.addIdentifier().setSystem("urn").setValue("123"); rpt.getText().setDivAsString("AAA"); rpt.addSpecimen().setResource(spm); @@ -472,7 +479,7 @@ public class XmlParserTest { Patient patient = new Patient(); patient.addAddress().setUse(AddressUse.HOME); - patient.addExtension().setUrl("urn:foo").setValue( new Reference("Organization/123")); + patient.addExtension().setUrl("urn:foo").setValue(new Reference("Organization/123")); String val = parser.encodeResourceToString(patient); ourLog.info(val); @@ -483,7 +490,7 @@ public class XmlParserTest { List ext = actual.getExtension(); assertEquals(1, ext.size()); Reference ref = (Reference) ext.get(0).getValue(); - assertEquals("Organization/123", ref.getReference()); + assertEquals("Organization/123", ref.getReference().getValue()); } @@ -565,7 +572,6 @@ public class XmlParserTest { } - @Test public void testEncodeResourceRef() throws DataFormatException { @@ -618,7 +624,7 @@ public class XmlParserTest { HumanName name = patient.addName(); name.addFamily("Shmoe"); HumanName given = name.addGiven("Joe"); - Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue( new StringType("Hello")); + Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue(new StringType("Hello")); given.getExtension().add(ext2); String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); ourLog.info(output); @@ -629,7 +635,7 @@ public class XmlParserTest { Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); assertEquals(1, parsed.getName().get(0).getExtension().size()); Extension ext = parsed.getName().get(0).getExtension().get(0); - assertEquals("Hello", ((IPrimitiveType)ext.getValue()).getValue()); + assertEquals("Hello", ((IPrimitiveType) ext.getValue()).getValue()); } @@ -642,7 +648,7 @@ public class XmlParserTest { StringType family = name.addFamilyElement(); family.setValue("Shmoe"); - Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue( new StringType("Hello")); + Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue(new StringType("Hello")); family.getExtension().add(ext2); String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); ourLog.info(output); @@ -653,7 +659,7 @@ public class XmlParserTest { Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); assertEquals(1, parsed.getName().get(0).getFamily().get(0).getExtension().size()); Extension ext = parsed.getName().get(0).getFamily().get(0).getExtension().get(0); - assertEquals("Hello", ((IPrimitiveType)ext.getValue()).getValue()); + assertEquals("Hello", ((IPrimitiveType) ext.getValue()).getValue()); } @@ -690,7 +696,7 @@ public class XmlParserTest { + "" + "" + "" - + "" + + "" + "
" + ""; //@formatter:on @@ -698,11 +704,13 @@ public class XmlParserTest { Patient patient = ourCtx.newXmlParser().parseResource(Patient.class, msg); assertEquals(NarrativeStatus.GENERATED, patient.getText().getStatus()); - assertEquals("
John Cardinal: 444333333
", patient.getText().getDiv().getValueAsString()); + assertEquals("
John Cardinal: 444333333
", patient.getText().getDiv().getValueAsString()); assertEquals("PRP1660", patient.getIdentifier().get(0).getValue()); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); - + + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient)); + Diff d = new Diff(new StringReader(msg), new StringReader(encoded)); assertTrue(d.toString(), d.identical()); @@ -801,12 +809,12 @@ public class XmlParserTest { Patient resource = (Patient) p.parseResource(msg); assertEquals("IdentifierLabel", resource.getIdentifier().get(0).getLabel()); - assertEquals("Foo1Value", ((IPrimitiveType)resource.getExtension().get(0).getValue()).getValueAsString()); - assertEquals("Foo1Value2", ((IPrimitiveType)resource.getExtension().get(1).getValue()).getValueAsString()); - assertEquals("Foo2Value1", ((IPrimitiveType)resource.getModifierExtension().get(0).getValue()).getValueAsString()); + assertEquals("Foo1Value", ((IPrimitiveType) resource.getExtension().get(0).getValue()).getValueAsString()); + assertEquals("Foo1Value2", ((IPrimitiveType) resource.getExtension().get(1).getValue()).getValueAsString()); + assertEquals("Foo2Value1", ((IPrimitiveType) resource.getModifierExtension().get(0).getValue()).getValueAsString()); - assertEquals("2013-01-01", ((IPrimitiveType)resource.getExtension().get(2).getExtension().get(0).getValue()).getValueAsString()); - assertEquals("2013-01-02", ((IPrimitiveType)resource.getExtension().get(2).getExtension().get(1).getExtension().get(0).getValue()).getValueAsString()); + assertEquals("2013-01-01", ((IPrimitiveType) resource.getExtension().get(2).getExtension().get(0).getValue()).getValueAsString()); + assertEquals("2013-01-02", ((IPrimitiveType) resource.getExtension().get(2).getExtension().get(1).getExtension().get(0).getValue()).getValueAsString()); String encoded = p.encodeResourceToString(resource); ourLog.info(encoded); @@ -815,51 +823,9 @@ public class XmlParserTest { assertTrue(d.toString(), d.identical()); } - @Test - public void testLoadObservation() throws ConfigurationException, DataFormatException, IOException { - - IParser p = ourCtx.newXmlParser(); - - String string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/observation-example-eeg.xml"), Charset.forName("UTF-8")); - IBaseResource resource = p.parseResource(string); - - String result = p.encodeResourceToString(resource); - ourLog.info(result); - } + - @Test - public void testLoadPatient() throws ConfigurationException, DataFormatException, IOException { - - IParser p = ourCtx.newXmlParser(); - - String string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/patient-example-dicom.xml"), Charset.forName("UTF-8")); - IBaseResource resource = p.parseResource(string); - - String result = p.encodeResourceToString(resource); - ourLog.info(result); - - // Nothing - - string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/patient-example-us-extensions.xml"), Charset.forName("UTF-8")); - resource = p.parseResource(string); - - result = p.encodeResourceToString(resource); - ourLog.info(result); - - } - - @Test - public void testLoadQuestionnaire() throws ConfigurationException, DataFormatException, IOException { - - IParser p = ourCtx.newXmlParser(); - - String string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/questionnaire-example.xml"), Charset.forName("UTF-8")); - IBaseResource resource = p.parseResource(string); - - String result = p.encodeResourceToString(resource); - ourLog.info(result); - } @Test public void testReEncode() throws SAXException, IOException { @@ -920,12 +886,10 @@ public class XmlParserTest { String enc = ourCtx.newXmlParser().encodeResourceToString(patient); assertThat(enc, containsString("")); assertThat(enc, containsString("")); - assertThat( - enc, - containsString("")); + assertThat(enc, containsString("")); assertThat(enc, containsString("")); assertThat(enc, containsString("")); - + /* * Now parse this back */ @@ -964,7 +928,8 @@ public class XmlParserTest { } - @Test + + // Narrative generation not currently supported for HL7org structures public void testNarrativeGeneration() throws DataFormatException, IOException { Patient patient = new Patient(); @@ -998,8 +963,9 @@ public class XmlParserTest { @Override public void setFhirContext(FhirContext theFhirContext) { // nothing - }}; - + } + }; + FhirContext context = new FhirContext(); context.setNarrativeGenerator(gen); IParser p = context.newXmlParser(); @@ -1075,7 +1041,6 @@ public class XmlParserTest { } - @Test public void testParseBundleWithMixedReturnTypes() { InputStreamReader str = new InputStreamReader(getClass().getResourceAsStream("/mixed-return-bundle.xml")); @@ -1141,7 +1106,6 @@ public class XmlParserTest { assertEquals("zh-CN", pt.getLanguage()); } - @Test public void testParseWithXmlHeader() throws ConfigurationException, DataFormatException { IParser p = ourCtx.newXmlParser(); @@ -1217,7 +1181,6 @@ public class XmlParserTest { } - @BeforeClass public static void beforeClass() { XMLUnit.setIgnoreAttributeOrder(true); diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/resources/example-patient-general.json b/hapi-fhir-structures-hl7org-dstu2/src/test/resources/example-patient-general.json new file mode 100644 index 00000000000..69e05527191 --- /dev/null +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/resources/example-patient-general.json @@ -0,0 +1,149 @@ +{ + "resourceType":"Patient", + "extension":[ + { + "url":"urn:patientext:att", + "valueAttachment":{ + "contentType":"aaaa", + "data":"AAAA" + } + }, + { + "url":"urn:patientext:moreext", + "extension":[ + { + "url":"urn:patientext:moreext:1", + "valueString":"str1" + }, + { + "url":"urn:patientext:moreext:2", + "valueString":"str2" + } + ] + } + ], + "modifierExtension":[ + { + "url":"urn:modext", + "valueDate":"2011-01-02" + } + ], + "text":{ + "status":"generated", + "div":"
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
NamePeter James Chalmers (\"Jim\")
Address534 Erewhon, Pleasantville, Vic, 3999
ContactsHome: unknown. Work: (03) 5555 6473
IdMRN: 12345 (Acme Healthcare)
\n
" + }, + "identifier":[ + { + "use":"usual", + "label":"MRN", + "system":"urn:oid:1.2.36.146.595.217.0.1", + "value":"12345", + "period":{ + "start":"2001-05-06" + }, + "assigner":{ + "display":"Acme Healthcare" + } + } + ], + "name":[ + { + "use":"official", + "family":[ + "Chalmers" + ], + "given":[ + "Peter", + "James" + ] + }, + { + "use":"usual", + "given":[ + "Jim" + ] + } + ], + "telecom":[ + { + "use":"home" + }, + { + "system":"phone", + "value":"(03) 5555 6473", + "use":"work" + } + ], + "gender":{ + "coding":[ + { + "system":"http://hl7.org/fhir/v3/AdministrativeGender", + "code":"M", + "display":"Male" + } + ] + }, + "birthDate":"1974-12-25", + "deceasedBoolean":false, + "address":[ + { + "use":"home", + "line":[ + "534 Erewhon St" + ], + "city":"PleasantVille", + "state":"Vic", + "zip":"3999" + }, + { + "use":"old", + "line":[ + "SecondAddress" + ] + } + ], + "contact":[ + { + "relationship":[ + { + "coding":[ + { + "system":"http://hl7.org/fhir/patient-contact-relationship", + "code":"partner" + } + ] + } + ], + "name":{ + "family":[ + "du", + "Marché" + ], + "_family":[ + { + "extension":[ + { + "url":"http://hl7.org/fhir/Profile/iso-21090#qualifier", + "valueCode":"VV" + } + ] + }, + null + ], + "given":[ + "Bénédicte" + ] + }, + "telecom":[ + { + "system":"phone", + "value":"+33 (237) 998327" + } + ] + } + ], + "managingOrganization":{ + "reference":"Organization/1" + }, + "active":true +} \ No newline at end of file