Dramatically improve the performance of containResourcesForEncoding

We do this by avoiding the double processing of contained resources when
looking for resources to contain
This commit is contained in:
David Maplesden 2019-09-10 11:11:45 +12:00 committed by James Agnew
parent 6475146bc9
commit 5120fe795e
1 changed files with 82 additions and 1 deletions

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
@ -235,7 +236,7 @@ public abstract class BaseParser implements IParser {
} }
} }
List<IBaseReference> allReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, IBaseReference.class); List<IBaseReference> allReferences = getAllBaseReferences(theResource);
for (IBaseReference next : allReferences) { for (IBaseReference next : allReferences) {
IBaseResource resource = next.getResource(); IBaseResource resource = next.getResource();
if (resource == null && next.getReferenceElement().isLocal()) { if (resource == null && next.getReferenceElement().isLocal()) {
@ -280,6 +281,86 @@ public abstract class BaseParser implements IParser {
} }
protected List<IBaseReference> getAllBaseReferences(IBaseResource theResource){
final ArrayList<IBaseReference> retVal = new ArrayList<IBaseReference>();
findBaseReferences(retVal, theResource, myContext.getResourceDefinition(theResource));
return retVal;
}
/**
* A customised traversal of the tree to find the 'top level' base references. Nested references are found via the recursive traversal
* of contained resources.
*/
protected void findBaseReferences(List<IBaseReference> allElements, IBase theElement, BaseRuntimeElementDefinition<?> theDefinition) {
if (theElement instanceof IBaseReference) {
allElements.add((IBaseReference) theElement);
}
BaseRuntimeElementDefinition<?> def = theDefinition;
if (def.getChildType() == ChildTypeEnum.CONTAINED_RESOURCE_LIST) {
def = myContext.getElementDefinition(theElement.getClass());
}
switch (def.getChildType()) {
case ID_DATATYPE:
case PRIMITIVE_XHTML_HL7ORG:
case PRIMITIVE_XHTML:
case PRIMITIVE_DATATYPE:
// These are primitive types
break;
case RESOURCE:
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> childDef = (BaseRuntimeElementCompositeDefinition<?>) def;
for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) {
List<?> values = nextChild.getAccessor().getValues(theElement);
if (values != null) {
for (Object nextValueObject : values) {
IBase nextValue;
try {
nextValue = (IBase) nextValueObject;
} catch (ClassCastException e) {
String s = "Found instance of " + nextValueObject.getClass() + " - Did you set a field value to the incorrect type? Expected " + IBase.class.getName();
throw new ClassCastException(s);
}
if (nextValue == null) {
continue;
}
if (nextValue.isEmpty()) {
continue;
}
BaseRuntimeElementDefinition<?> childElementDef;
childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
if (childElementDef == null) {
childElementDef = myContext.getElementDefinition(nextValue.getClass());
}
if (nextChild instanceof RuntimeChildDirectResource) {
// Don't descend into embedded resources
if (nextValue instanceof IBaseReference) {
allElements.add((IBaseReference) nextValue);
}
} else {
findBaseReferences(allElements, nextValue, childElementDef);
}
}
}
}
break;
}
case CONTAINED_RESOURCES:
// skip contained resources when looking for resources to contain
break;
case CONTAINED_RESOURCE_LIST:
case EXTENSION_DECLARED:
case UNDECL_EXT: {
throw new IllegalStateException("state should not happen: " + def.getChildType());
}
}
}
private String determineReferenceText(IBaseReference theRef, CompositeChildElement theCompositeChildElement) { private String determineReferenceText(IBaseReference theRef, CompositeChildElement theCompositeChildElement) {
IIdType ref = theRef.getReferenceElement(); IIdType ref = theRef.getReferenceElement();
if (isBlank(ref.getIdPart())) { if (isBlank(ref.getIdPart())) {