Skip to content

Commit

Permalink
Clean up parsers so that elements are always encoded according to the…
Browse files Browse the repository at this point in the history
…ir order in the structures that contain them
  • Loading branch information
jamesagnew committed Apr 11, 2016
1 parent 364f11a commit 2f37015
Show file tree
Hide file tree
Showing 52 changed files with 2,364 additions and 896 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,17 @@ public void testParseResourceReference() {

String res = ourCtxDstu1.newXmlParser().encodeResourceToString(p);

{
ca.uhn.fhir.model.dstu2.resource.Patient parsed = ourCtxDstu1.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Patient.class, res);
assertEquals("RR Display", parsed.getManagingOrganization().getDisplayElement().getValue());
assertEquals(1, parsed.getContained().getContainedResources().size());
assertEquals("<div>DIV</div>", p.getText().getDiv().getValueAsString());

try {
ourCtxDstu1.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Patient.class, res);
fail();
} catch (IllegalArgumentException e) {
assertEquals("This parser is for FHIR version DSTU1 - Can not parse a structure for version DSTU2", e.getMessage());
}
{
ca.uhn.fhir.model.dstu.resource.Patient parsed = ourCtxDstu2.newXmlParser().parseResource(ca.uhn.fhir.model.dstu.resource.Patient.class, res);
assertEquals("RR Display", parsed.getManagingOrganization().getDisplayElement().getValue());
assertEquals(1, parsed.getContained().getContainedResources().size());
assertEquals("<div>DIV</div>", p.getText().getDiv().getValueAsString());
try {
ourCtxDstu2.newXmlParser().parseResource(ca.uhn.fhir.model.dstu.resource.Patient.class, res);
fail();
} catch (IllegalArgumentException e) {
assertEquals("This parser is for FHIR version DSTU2 - Can not parse a structure for version DSTU1", e.getMessage());
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseReference;

public abstract class BaseRuntimeChildDefinition {

Expand Down Expand Up @@ -73,6 +75,17 @@ public interface IMutator {
void setValue(Object theTarget, IBase theValue);
}

BaseRuntimeElementDefinition<?> findResourceReferenceDefinition(Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
for (Entry<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> next : theClassToElementDefinitions.entrySet()) {
if (IBaseReference.class.isAssignableFrom(next.getKey())) {
return next.getValue();
}
}

// Shouldn't happen
throw new IllegalStateException("Unable to find reference type");
}

// public String getExtensionUrl() {
// return null;
// }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
private final int myMin;
private boolean myModifier;
private final IMutator myMutator;

private final String myShortDefinition;
private boolean mySummary;

BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException {
super();
Validate.notNull(theField, "No field speficied");
Expand Down Expand Up @@ -124,10 +124,15 @@ public boolean isModifier() {
return myModifier;
}

@Override
public boolean isSummary() {
return mySummary;
}

protected void setModifier(boolean theModifier) {
myModifier = theModifier;
}

private final class FieldListAccessor implements IAccessor {
@SuppressWarnings("unchecked")
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.TreeSet;

Expand Down Expand Up @@ -51,16 +52,16 @@ void addChild(BaseRuntimeChildDefinition theNext) {
myChildren.add(theNext);
}

public BaseRuntimeChildDefinition getChildByNameOrThrowDataFormatException(String theName) throws DataFormatException {
public BaseRuntimeChildDefinition getChildByName(String theName){
BaseRuntimeChildDefinition retVal = myNameToChild.get(theName);
if (retVal == null) {
throw new DataFormatException("Unknown child name '" + theName + "' in element " + getName() + " - Valid names are: " + new TreeSet<String>(myNameToChild.keySet()));
}
return retVal;
}

public BaseRuntimeChildDefinition getChildByName(String theName){
public BaseRuntimeChildDefinition getChildByNameOrThrowDataFormatException(String theName) throws DataFormatException {
BaseRuntimeChildDefinition retVal = myNameToChild.get(theName);
if (retVal == null) {
throw new DataFormatException("Unknown child name '" + theName + "' in element " + getName() + " - Valid names are: " + new TreeSet<String>(myNameToChild.keySet()));
}
return retVal;
}

Expand All @@ -72,8 +73,8 @@ public List<BaseRuntimeChildDefinition> getChildrenAndExtension() {
return myChildrenAndExtensions;
}

@Override
public void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
@Override
void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
super.sealAndInitialize(theContext, theClassToElementDefinitions);

for (BaseRuntimeChildDefinition next : myChildren) {
Expand All @@ -100,9 +101,25 @@ public void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>

List<BaseRuntimeChildDefinition> children = new ArrayList<BaseRuntimeChildDefinition>();
children.addAll(myChildren);
children.addAll(getExtensionsModifier());
children.addAll(getExtensionsNonModifier());
if (getExtensionsNonModifier().isEmpty() == false) {
children.addAll(findIndex(children, "extension"), getExtensionsNonModifier());
}
if (getExtensionsModifier().isEmpty() == false) {
children.addAll(findIndex(children, "modifierExtension"), getExtensionsModifier());
}

myChildrenAndExtensions=Collections.unmodifiableList(children);
}

private static int findIndex(List<BaseRuntimeChildDefinition> theChildren, String theName) {
int index = theChildren.size();
for (ListIterator<BaseRuntimeChildDefinition> iter = theChildren.listIterator(); iter.hasNext(); ) {
if (iter.next().getElementName().equals(theName)) {
index = iter.previousIndex();
break;
}
}
return index;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,13 @@ private void scanCompositeElementForChildren(Class<? extends IBase> theClass, Se

Class<?> nextElementType = determineElementType(next);

if (BaseContainedDt.class.isAssignableFrom(nextElementType) || (childAnnotation.name().equals("contained") && IBaseResource.class.isAssignableFrom(nextElementType))) {
if (childAnnotation.name().equals("extension") && IBaseExtension.class.isAssignableFrom(nextElementType)) {
RuntimeChildExtension def = new RuntimeChildExtension(next, childAnnotation.name(), childAnnotation, descriptionAnnotation);
orderMap.put(order, def);
} else if (childAnnotation.name().equals("modifierExtension") && IBaseExtension.class.isAssignableFrom(nextElementType)) {
RuntimeChildExtension def = new RuntimeChildExtension(next, childAnnotation.name(), childAnnotation, descriptionAnnotation);
orderMap.put(order, def);
} else if (BaseContainedDt.class.isAssignableFrom(nextElementType) || (childAnnotation.name().equals("contained") && IBaseResource.class.isAssignableFrom(nextElementType))) {
/*
* Child is contained resources
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -101,8 +102,7 @@ void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseR
elementName = getElementName() + StringUtils.capitalize(next.getSimpleName());
List<Class<? extends IBaseResource>> types = new ArrayList<Class<? extends IBaseResource>>();
types.add((Class<? extends IBaseResource>) next);
nextDef = new RuntimeResourceReferenceDefinition(elementName, types, false);
nextDef.sealAndInitialize(theContext, theClassToElementDefinitions);
nextDef = findResourceReferenceDefinition(theClassToElementDefinitions);

myNameToChildDefinition.put(getElementName() + "Reference", nextDef);
myNameToChildDefinition.put(getElementName() + "Resource", nextDef);
Expand Down Expand Up @@ -169,6 +169,7 @@ void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseR

}


@Override
public String getChildNameByDatatype(Class<? extends IBase> theDatatype) {
String retVal = myDatatypeToElementName.get(theDatatype);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public boolean isDefinedLocally() {
return myDefinedLocally;
}

@Override
public boolean isModifier() {
return myModifier;
}
Expand All @@ -164,7 +165,7 @@ void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseR
myDatatypeChildName = "valueResource";
List<Class<? extends IBaseResource>> types = new ArrayList<Class<? extends IBaseResource>>();
types.add(IResource.class);
myChildDef = new RuntimeResourceReferenceDefinition("valueResource", types, false);
myChildDef = findResourceReferenceDefinition(theClassToElementDefinitions);
} else {
myChildDef = elementDef;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ca.uhn.fhir.context;

import static org.hamcrest.Matchers.emptyCollectionOf;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseExtension;

import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;

public class RuntimeChildExtension extends RuntimeChildAny {

private RuntimeChildUndeclaredExtensionDefinition myExtensionElement;

public RuntimeChildExtension(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation) {
super(theField, theElementName, theChildAnnotation, theDescriptionAnnotation);
}

@Override
public String getChildNameByDatatype(Class<? extends IBase> theDatatype) {
return getElementName();
}

@Override
public Set<String> getValidChildNames() {
return Collections.singleton(getElementName());
}

// @Override
// public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IBase> theDatatype) {
// if (IBaseExtension.class.isAssignableFrom(theDatatype)) {
// return myExtensionElement;
// }
// return super.getChildElementDefinitionByDatatype(theDatatype);
// }
//
// @Override
// void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
// super.sealAndInitialize(theContext, theClassToElementDefinitions);
//
// myExtensionElement = theContext.getRuntimeChildUndeclaredExtensionDefinition();
// }


}
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ public BaseRuntimeElementDefinition<?> getChildByName(String theName) {

@Override
void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
myRuntimeDef = new RuntimeResourceReferenceDefinition(getElementName(), myResourceTypes, false);
myRuntimeDef.sealAndInitialize(theContext, theClassToElementDefinitions);
myRuntimeDef = findResourceReferenceDefinition(theClassToElementDefinitions);

myValidChildNames = new HashSet<String>();
myValidChildNames.add(getElementName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ public RuntimeChildUndeclaredExtensionDefinition() {
private void addReferenceBinding(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions, String value) {
List<Class<? extends IBaseResource>> types = new ArrayList<Class<? extends IBaseResource>>();
types.add(IBaseResource.class);
RuntimeResourceReferenceDefinition def = new RuntimeResourceReferenceDefinition(value, types, false);
def.sealAndInitialize(theContext, theClassToElementDefinitions);
BaseRuntimeElementDefinition<?> def = findResourceReferenceDefinition(theClassToElementDefinitions);

myAttributeNameToDefinition.put(value, def);
/*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,83 +1,25 @@
package ca.uhn.fhir.context;

/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 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.HashMap;
import java.util.List;
import java.util.Map;

import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;

import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;

public class RuntimeResourceReferenceDefinition extends BaseRuntimeElementDefinition<BaseResourceReferenceDt> {
import org.hl7.fhir.instance.model.api.IBaseReference;

private final List<Class<? extends IBaseResource>> myResourceTypes;
private HashMap<Class<? extends IBaseResource>, RuntimeResourceDefinition> myResourceTypeToDefinition;
public class RuntimeResourceReferenceDefinition extends BaseRuntimeElementCompositeDefinition<IBaseReference> {

/**
* Constructor
* @param theStandardType
*/
public RuntimeResourceReferenceDefinition(String theName, List<Class<? extends IBaseResource>> theResourceTypes, boolean theStandardType) {
super(theName, BaseResourceReferenceDt.class, theStandardType);
if (theResourceTypes == null || theResourceTypes.isEmpty()) {
throw new ConfigurationException("Element '" + theName + "' has no resource types noted");
}
myResourceTypes = theResourceTypes;
}

public List<Class<? extends IBaseResource>> getResourceTypes() {
return myResourceTypes;
public RuntimeResourceReferenceDefinition(String theName, Class<? extends IBaseReference> theImplementingClass, boolean theStandardType) {
super(theName, theImplementingClass, theStandardType);
}

@Override
void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
myResourceTypeToDefinition = new HashMap<Class<? extends IBaseResource>, RuntimeResourceDefinition>();
for (Class<? extends IBaseResource> next : myResourceTypes) {
if (next.equals(IResource.class) || next.equals(IAnyResource.class) || next.equals(IBaseResource.class)) {
continue;
}
RuntimeResourceDefinition definition = (RuntimeResourceDefinition) theClassToElementDefinitions.get(next);
if (definition == null) {
throw new ConfigurationException("Couldn't find definition for: " + next.getCanonicalName());
}
myResourceTypeToDefinition.put(next, definition);
}
super.sealAndInitialize(theContext, theClassToElementDefinitions);
}

@Override
public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
return ChildTypeEnum.RESOURCE_REF;
}

public RuntimeResourceDefinition getDefinitionForResourceType(Class<? extends IResource> theType) {
RuntimeResourceDefinition retVal = myResourceTypeToDefinition.get(theType);
if (retVal == null) {
throw new ConfigurationException("Unknown type: " + theType.getCanonicalName());
}
return retVal;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,23 @@
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseDatatype;

import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;

public abstract class BaseElement implements IElement, ISupportsUndeclaredExtensions {

private List<String> myFormatCommentsPost;
private List<String> myFormatCommentsPre;

@Child(name = "extension", type = {ExtensionDt.class}, order=0, min=0, max=Child.MAX_UNLIMITED, modifier=false, summary=false)
@Description(shortDefinition="Additional Content defined by implementations", formalDefinition="May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension." )
private List<ExtensionDt> myUndeclaredExtensions;

/**
* May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.
*/
@Child(name = "modifierExtension", type = {ExtensionDt.class}, order=1, min=0, max=Child.MAX_UNLIMITED, modifier=true, summary=false)
@Description(shortDefinition="Extensions that cannot be ignored", formalDefinition="May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions." )
private List<ExtensionDt> myUndeclaredModifierExtensions;

@Override
Expand Down
Loading

0 comments on commit 2f37015

Please sign in to comment.