Refactor the way that contexts are used in narrative generator
This commit is contained in:
parent
f934f76c96
commit
71a07c0239
|
@ -36,16 +36,16 @@ public abstract class BaseThymeleafNarrativeGenerator extends ThymeleafNarrative
|
|||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public BaseThymeleafNarrativeGenerator(FhirContext theFhirContext) {
|
||||
super(theFhirContext);
|
||||
public BaseThymeleafNarrativeGenerator() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean populateResourceNarrative(IBaseResource theResource) {
|
||||
public boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource) {
|
||||
if (!myInitialized) {
|
||||
initialize();
|
||||
}
|
||||
super.populateResourceNarrative(theResource);
|
||||
super.populateResourceNarrative(theFhirContext, theResource);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ public abstract class BaseThymeleafNarrativeGenerator extends ThymeleafNarrative
|
|||
|
||||
List<String> propFileName = getPropertyFile();
|
||||
try {
|
||||
NarrativeTemplateManifest manifest = NarrativeTemplateManifest.forManifestFileLocation(getFhirContext(), propFileName);
|
||||
NarrativeTemplateManifest manifest = NarrativeTemplateManifest.forManifestFileLocation(propFileName);
|
||||
setManifest(manifest);
|
||||
} catch (IOException e) {
|
||||
throw new InternalErrorException(e);
|
||||
|
|
|
@ -40,8 +40,8 @@ public class CustomThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGen
|
|||
* <li>classpath:/com/package/file.properties</li>
|
||||
* </ul>
|
||||
*/
|
||||
public CustomThymeleafNarrativeGenerator(FhirContext theFhirContext, String... thePropertyFile) {
|
||||
super(theFhirContext);
|
||||
public CustomThymeleafNarrativeGenerator(String... thePropertyFile) {
|
||||
super();
|
||||
setPropertyFile(thePropertyFile);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ package ca.uhn.fhir.narrative;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -32,8 +30,8 @@ public class DefaultThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGe
|
|||
|
||||
private boolean myUseHapiServerConformanceNarrative;
|
||||
|
||||
public DefaultThymeleafNarrativeGenerator(FhirContext theFhirContext) {
|
||||
super(theFhirContext);
|
||||
public DefaultThymeleafNarrativeGenerator() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.narrative;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
public interface INarrativeGenerator {
|
||||
|
@ -32,6 +33,6 @@ public interface INarrativeGenerator {
|
|||
*
|
||||
* @return Returns <code>true</code> if a narrative was actually generated
|
||||
*/
|
||||
boolean populateResourceNarrative(IBaseResource theResource);
|
||||
boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,14 +27,13 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
|||
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.INarrative;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -44,12 +43,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
|
||||
|
||||
private INarrativeTemplateManifest myManifest;
|
||||
private final FhirContext myFhirContext;
|
||||
|
||||
public BaseNarrativeGenerator(FhirContext theFhirContext) {
|
||||
Validate.notNull(theFhirContext, "theFhirContext must not be null");
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
public INarrativeTemplateManifest getManifest() {
|
||||
return myManifest;
|
||||
|
@ -59,43 +52,40 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
|
|||
myManifest = theManifest;
|
||||
}
|
||||
|
||||
public FhirContext getFhirContext() {
|
||||
return myFhirContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean populateResourceNarrative(IBaseResource theResource) {
|
||||
Optional<INarrativeTemplate> templateOpt = getTemplateForElement(theResource);
|
||||
if (templateOpt.isPresent()) {
|
||||
return applyTemplate(templateOpt.get(), theResource);
|
||||
} else {
|
||||
return false;
|
||||
public boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource) {
|
||||
List<INarrativeTemplate> templateOpt = getTemplateForElement(theFhirContext, theResource);
|
||||
if (templateOpt.size() > 0) {
|
||||
applyTemplate(theFhirContext, templateOpt.get(0), theResource);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Optional<INarrativeTemplate> getTemplateForElement(IBase theElement) {
|
||||
return myManifest.getTemplateByElement(getStyle(), theElement);
|
||||
private List<INarrativeTemplate> getTemplateForElement(FhirContext theFhirContext, IBase theElement) {
|
||||
return myManifest.getTemplateByElement(theFhirContext, getStyle(), theElement);
|
||||
}
|
||||
|
||||
private boolean applyTemplate(INarrativeTemplate theTemplate, IBaseResource theResource) {
|
||||
private boolean applyTemplate(FhirContext theFhirContext, INarrativeTemplate theTemplate, IBaseResource theResource) {
|
||||
if (templateDoesntApplyToResource(theTemplate, theResource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean retVal = false;
|
||||
String resourceName = myFhirContext.getResourceDefinition(theResource).getName();
|
||||
String resourceName = theFhirContext.getResourceDefinition(theResource).getName();
|
||||
String contextPath = defaultIfEmpty(theTemplate.getContextPath(), resourceName);
|
||||
|
||||
// Narrative templates define a path within the resource that they apply to. Here, we're
|
||||
// finding anywhere in the resource that gets a narrative
|
||||
List<IBase> targets = findElementsInResourceRequiringNarratives(theResource, contextPath);
|
||||
List<IBase> targets = findElementsInResourceRequiringNarratives(theFhirContext, theResource, contextPath);
|
||||
for (IBase nextTargetContext : targets) {
|
||||
|
||||
// Extract [element].text of type Narrative
|
||||
INarrative nextTargetNarrative = getOrCreateNarrativeChildElement(nextTargetContext);
|
||||
INarrative nextTargetNarrative = getOrCreateNarrativeChildElement(theFhirContext, nextTargetContext);
|
||||
|
||||
// Create the actual narrative text
|
||||
String narrative = applyTemplate(theTemplate, nextTargetContext);
|
||||
String narrative = applyTemplate(theFhirContext, theTemplate, nextTargetContext);
|
||||
narrative = cleanWhitespace(narrative);
|
||||
|
||||
if (isNotBlank(narrative)) {
|
||||
|
@ -112,13 +102,13 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private INarrative getOrCreateNarrativeChildElement(IBase nextTargetContext) {
|
||||
BaseRuntimeElementCompositeDefinition<?> targetElementDef = (BaseRuntimeElementCompositeDefinition<?>) getFhirContext().getElementDefinition(nextTargetContext.getClass());
|
||||
private INarrative getOrCreateNarrativeChildElement(FhirContext theFhirContext, IBase nextTargetContext) {
|
||||
BaseRuntimeElementCompositeDefinition<?> targetElementDef = (BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition(nextTargetContext.getClass());
|
||||
BaseRuntimeChildDefinition targetTextChild = targetElementDef.getChildByName("text");
|
||||
List<IBase> existing = targetTextChild.getAccessor().getValues(nextTargetContext);
|
||||
INarrative nextTargetNarrative;
|
||||
if (existing.isEmpty()) {
|
||||
nextTargetNarrative = (INarrative) getFhirContext().getElementDefinition("narrative").newInstance();
|
||||
nextTargetNarrative = (INarrative) theFhirContext.getElementDefinition("narrative").newInstance();
|
||||
targetTextChild.getMutator().addValue(nextTargetContext, nextTargetNarrative);
|
||||
} else {
|
||||
nextTargetNarrative = (INarrative) existing.get(0);
|
||||
|
@ -126,15 +116,15 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
|
|||
return nextTargetNarrative;
|
||||
}
|
||||
|
||||
private List<IBase> findElementsInResourceRequiringNarratives(IBaseResource theResource, String theContextPath) {
|
||||
if (myFhirContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
|
||||
private List<IBase> findElementsInResourceRequiringNarratives(FhirContext theFhirContext, IBaseResource theResource, String theContextPath) {
|
||||
if (theFhirContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
|
||||
return Collections.singletonList(theResource);
|
||||
}
|
||||
IFluentPath fhirPath = myFhirContext.newFluentPath();
|
||||
IFluentPath fhirPath = theFhirContext.newFluentPath();
|
||||
return fhirPath.evaluate(theResource, theContextPath, IBase.class);
|
||||
}
|
||||
|
||||
protected abstract String applyTemplate(INarrativeTemplate theTemplate, IBase theTargetContext);
|
||||
protected abstract String applyTemplate(FhirContext theFhirContext, INarrativeTemplate theTemplate, IBase theTargetContext);
|
||||
|
||||
private boolean templateDoesntApplyToResource(INarrativeTemplate theTemplate, IBaseResource theResource) {
|
||||
boolean retVal = false;
|
||||
|
@ -156,7 +146,7 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
protected abstract TemplateTypeEnum getStyle();
|
||||
protected abstract EnumSet<TemplateTypeEnum> getStyle();
|
||||
|
||||
/**
|
||||
* Trims the superfluous whitespace out of an HTML block
|
||||
|
@ -188,7 +178,6 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
|
|||
if (inWhitespace && !lastNonWhitespaceCharWasTagEnd) {
|
||||
b.append(' ');
|
||||
}
|
||||
inWhitespace = false;
|
||||
b.append(nextChar);
|
||||
inWhitespace = false;
|
||||
betweenTags = false;
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.narrative2;
|
|||
* 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.
|
||||
|
@ -20,14 +20,16 @@ package ca.uhn.fhir.narrative2;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
public interface INarrativeTemplateManifest {
|
||||
Optional<INarrativeTemplate> getTemplateByResourceName(TemplateTypeEnum theStyle, String theResourceName);
|
||||
List<INarrativeTemplate> getTemplateByResourceName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theResourceName);
|
||||
|
||||
Optional<INarrativeTemplate> getTemplateByName(TemplateTypeEnum theStyle, String theName);
|
||||
List<INarrativeTemplate> getTemplateByName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theName);
|
||||
|
||||
Optional<INarrativeTemplate> getTemplateByElement(TemplateTypeEnum theStyle, IBase theElementValue);
|
||||
List<INarrativeTemplate> getTemplateByElement(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, IBase theElementValue);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.narrative2;
|
|||
* 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.
|
||||
|
@ -34,41 +34,37 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(NarrativeTemplateManifest.class);
|
||||
|
||||
private final Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> myStyleToResourceTypeToTemplate;
|
||||
private final Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> myStyleToDatatypeToTemplate;
|
||||
private final Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> myStyleToNameToTemplate;
|
||||
private final FhirContext myCtx;
|
||||
private final Map<String, List<NarrativeTemplate>> myStyleToResourceTypeToTemplate;
|
||||
private final Map<String, List<NarrativeTemplate>> myStyleToDatatypeToTemplate;
|
||||
private final Map<String, List<NarrativeTemplate>> myStyleToNameToTemplate;
|
||||
private final int myTemplateCount;
|
||||
|
||||
private NarrativeTemplateManifest(FhirContext theFhirContext, Collection<NarrativeTemplate> theTemplates) {
|
||||
myCtx = theFhirContext;
|
||||
Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> styleToResourceTypeToTemplate = new HashMap<>();
|
||||
Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> styleToDatatypeToTemplate = new HashMap<>();
|
||||
Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> styleToNameToTemplate = new HashMap<>();
|
||||
private NarrativeTemplateManifest(Collection<NarrativeTemplate> theTemplates) {
|
||||
Map<String, List<NarrativeTemplate>> resourceTypeToTemplate = new HashMap<>();
|
||||
Map<String, List<NarrativeTemplate>> datatypeToTemplate = new HashMap<>();
|
||||
Map<String, List<NarrativeTemplate>> nameToTemplate = new HashMap<>();
|
||||
|
||||
for (NarrativeTemplate nextTemplate : theTemplates) {
|
||||
Map<String, NarrativeTemplate> resourceTypeToTemplate = styleToResourceTypeToTemplate.computeIfAbsent(nextTemplate.getTemplateType(), t -> new HashMap<>());
|
||||
Map<String, NarrativeTemplate> datatypeToTemplate = styleToDatatypeToTemplate.computeIfAbsent(nextTemplate.getTemplateType(), t -> new HashMap<>());
|
||||
Map<String, NarrativeTemplate> nameToTemplate = styleToNameToTemplate.computeIfAbsent(nextTemplate.getTemplateType(), t -> new HashMap<>());
|
||||
nameToTemplate.put(nextTemplate.getTemplateName(), nextTemplate);
|
||||
nameToTemplate.computeIfAbsent(nextTemplate.getTemplateName(), t -> new ArrayList<>()).add(nextTemplate);
|
||||
for (String nextResourceType : nextTemplate.getAppliesToResourceTypes()) {
|
||||
resourceTypeToTemplate.put(nextResourceType.toUpperCase(), nextTemplate);
|
||||
resourceTypeToTemplate.computeIfAbsent(nextResourceType.toUpperCase(), t -> new ArrayList<>()).add(nextTemplate);
|
||||
}
|
||||
for (String nextDataType : nextTemplate.getAppliesToDataTypes()) {
|
||||
datatypeToTemplate.put(nextDataType.toUpperCase(), nextTemplate);
|
||||
datatypeToTemplate.computeIfAbsent(nextDataType.toUpperCase(), t -> new ArrayList<>()).add(nextTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
myTemplateCount = theTemplates.size();
|
||||
myStyleToNameToTemplate = makeImmutable(styleToNameToTemplate);
|
||||
myStyleToResourceTypeToTemplate = makeImmutable(styleToResourceTypeToTemplate);
|
||||
myStyleToDatatypeToTemplate = makeImmutable(styleToDatatypeToTemplate);
|
||||
myStyleToNameToTemplate = makeImmutable(nameToTemplate);
|
||||
myStyleToResourceTypeToTemplate = makeImmutable(resourceTypeToTemplate);
|
||||
myStyleToDatatypeToTemplate = makeImmutable(datatypeToTemplate);
|
||||
}
|
||||
|
||||
public int getNamedTemplateCount() {
|
||||
|
@ -76,31 +72,31 @@ public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<INarrativeTemplate> getTemplateByResourceName(TemplateTypeEnum theStyle, String theResourceName) {
|
||||
return getFromMap(theStyle, theResourceName.toUpperCase(), myStyleToResourceTypeToTemplate);
|
||||
public List<INarrativeTemplate> getTemplateByResourceName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theResourceName) {
|
||||
return getFromMap(theStyles, theResourceName.toUpperCase(), myStyleToResourceTypeToTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<INarrativeTemplate> getTemplateByName(TemplateTypeEnum theStyle, String theName) {
|
||||
return getFromMap(theStyle, theName, myStyleToNameToTemplate);
|
||||
public List<INarrativeTemplate> getTemplateByName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theName) {
|
||||
return getFromMap(theStyles, theName, myStyleToNameToTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<INarrativeTemplate> getTemplateByElement(TemplateTypeEnum theStyle, IBase theElement) {
|
||||
public List<INarrativeTemplate> getTemplateByElement(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, IBase theElement) {
|
||||
if (theElement instanceof IBaseResource) {
|
||||
String resourceName = myCtx.getResourceDefinition((IBaseResource) theElement).getName();
|
||||
return getTemplateByResourceName(theStyle, resourceName);
|
||||
String resourceName = theFhirContext.getResourceDefinition((IBaseResource) theElement).getName();
|
||||
return getTemplateByResourceName(theFhirContext, theStyles, resourceName);
|
||||
} else {
|
||||
String datatypeName = myCtx.getElementDefinition(theElement.getClass()).getName();
|
||||
return getFromMap(theStyle, datatypeName.toUpperCase(), myStyleToDatatypeToTemplate);
|
||||
String datatypeName = theFhirContext.getElementDefinition(theElement.getClass()).getName();
|
||||
return getFromMap(theStyles, datatypeName.toUpperCase(), myStyleToDatatypeToTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
public static NarrativeTemplateManifest forManifestFileLocation(FhirContext theFhirContext, String... thePropertyFilePaths) throws IOException {
|
||||
return forManifestFileLocation(theFhirContext, Arrays.asList(thePropertyFilePaths));
|
||||
return forManifestFileLocation(Arrays.asList(thePropertyFilePaths));
|
||||
}
|
||||
|
||||
public static NarrativeTemplateManifest forManifestFileLocation(FhirContext theFhirContext, Collection<String> thePropertyFilePaths) throws IOException {
|
||||
public static NarrativeTemplateManifest forManifestFileLocation(Collection<String> thePropertyFilePaths) throws IOException {
|
||||
ourLog.debug("Loading narrative properties file(s): {}", thePropertyFilePaths);
|
||||
|
||||
List<String> manifestFileContents = new ArrayList<>(thePropertyFilePaths.size());
|
||||
|
@ -109,19 +105,19 @@ public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
|
|||
manifestFileContents.add(resource);
|
||||
}
|
||||
|
||||
return forManifestFileContents(theFhirContext, manifestFileContents);
|
||||
return forManifestFileContents(manifestFileContents);
|
||||
}
|
||||
|
||||
public static NarrativeTemplateManifest forManifestFileContents(FhirContext theFhirContext, String... theResources) throws IOException {
|
||||
return forManifestFileContents(theFhirContext, Arrays.asList(theResources));
|
||||
public static NarrativeTemplateManifest forManifestFileContents(String... theResources) throws IOException {
|
||||
return forManifestFileContents(Arrays.asList(theResources));
|
||||
}
|
||||
|
||||
public static NarrativeTemplateManifest forManifestFileContents(FhirContext theFhirContext, Collection<String> theResources) throws IOException {
|
||||
public static NarrativeTemplateManifest forManifestFileContents(Collection<String> theResources) throws IOException {
|
||||
List<NarrativeTemplate> templates = new ArrayList<>();
|
||||
for (String next : theResources) {
|
||||
templates.addAll(loadProperties(next));
|
||||
}
|
||||
return new NarrativeTemplateManifest(theFhirContext, templates);
|
||||
return new NarrativeTemplateManifest(templates);
|
||||
}
|
||||
|
||||
private static Collection<NarrativeTemplate> loadProperties(String theManifestText) throws IOException {
|
||||
|
@ -222,17 +218,16 @@ public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
|
|||
}
|
||||
}
|
||||
|
||||
private static <T> Optional<INarrativeTemplate> getFromMap(TemplateTypeEnum theStyle, T theResourceName, Map<TemplateTypeEnum, Map<T, NarrativeTemplate>> theMap) {
|
||||
NarrativeTemplate retVal = null;
|
||||
Map<T, NarrativeTemplate> resourceTypeToTemplate = theMap.get(theStyle);
|
||||
if (resourceTypeToTemplate != null) {
|
||||
retVal = resourceTypeToTemplate.get(theResourceName);
|
||||
}
|
||||
return Optional.ofNullable(retVal);
|
||||
private static <T> List<INarrativeTemplate> getFromMap(EnumSet<TemplateTypeEnum> theStyles, T theKey, Map<T, List<NarrativeTemplate>> theMap) {
|
||||
return theMap
|
||||
.getOrDefault(theKey, Collections.emptyList())
|
||||
.stream()
|
||||
.filter(t->theStyles.contains(t.getTemplateType()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static <T> Map<TemplateTypeEnum, Map<T, NarrativeTemplate>> makeImmutable(Map<TemplateTypeEnum, Map<T, NarrativeTemplate>> theStyleToResourceTypeToTemplate) {
|
||||
theStyleToResourceTypeToTemplate.replaceAll((key, value) -> Collections.unmodifiableMap(value));
|
||||
private static <T> Map<T, List<NarrativeTemplate>> makeImmutable(Map<T, List<NarrativeTemplate>> theStyleToResourceTypeToTemplate) {
|
||||
theStyleToResourceTypeToTemplate.replaceAll((key, value) -> Collections.unmodifiableList(value));
|
||||
return Collections.unmodifiableMap(theStyleToResourceTypeToTemplate);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,13 @@ package ca.uhn.fhir.narrative2;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
public class NullNarrativeGenerator implements INarrativeGenerator {
|
||||
@Override
|
||||
public boolean populateResourceNarrative(IBaseResource theResource) {
|
||||
public boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,9 +45,7 @@ import org.thymeleaf.templateresolver.DefaultTemplateResolver;
|
|||
import org.thymeleaf.templateresource.ITemplateResource;
|
||||
import org.thymeleaf.templateresource.StringTemplateResource;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
|
@ -58,13 +56,13 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ThymeleafNarrativeGenerator(FhirContext theFhirContext) {
|
||||
super(theFhirContext);
|
||||
public ThymeleafNarrativeGenerator() {
|
||||
super();
|
||||
}
|
||||
|
||||
private TemplateEngine getTemplateEngine() {
|
||||
private TemplateEngine getTemplateEngine(FhirContext theFhirContext) {
|
||||
TemplateEngine engine = new TemplateEngine();
|
||||
ProfileResourceResolver resolver = new ProfileResourceResolver();
|
||||
ProfileResourceResolver resolver = new ProfileResourceResolver(theFhirContext);
|
||||
engine.setTemplateResolver(resolver);
|
||||
if (myMessageResolver != null) {
|
||||
engine.setMessageResolver(myMessageResolver);
|
||||
|
@ -73,8 +71,8 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
@Override
|
||||
public Set<IProcessor> getProcessors(String theDialectPrefix) {
|
||||
Set<IProcessor> retVal = super.getProcessors(theDialectPrefix);
|
||||
retVal.add(new NarrativeTagProcessor(theDialectPrefix));
|
||||
retVal.add(new NarrativeAttributeProcessor(theDialectPrefix));
|
||||
retVal.add(new NarrativeTagProcessor(theFhirContext, theDialectPrefix));
|
||||
retVal.add(new NarrativeAttributeProcessor(theDialectPrefix, theFhirContext));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -85,25 +83,23 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String applyTemplate(INarrativeTemplate theTemplate, IBase theTargetContext) {
|
||||
protected String applyTemplate(FhirContext theFhirContext, INarrativeTemplate theTemplate, IBase theTargetContext) {
|
||||
|
||||
Context context = new Context();
|
||||
context.setVariable("resource", theTargetContext);
|
||||
context.setVariable("context", theTargetContext);
|
||||
context.setVariable("fhirVersion", getFhirContext().getVersion().getVersion().name());
|
||||
context.setVariable("fhirVersion", theFhirContext.getVersion().getVersion().name());
|
||||
|
||||
String result = getTemplateEngine().process(theTemplate.getTemplateName(), context);
|
||||
|
||||
return result;
|
||||
return getTemplateEngine(theFhirContext).process(theTemplate.getTemplateName(), context);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected TemplateTypeEnum getStyle() {
|
||||
return TemplateTypeEnum.THYMELEAF;
|
||||
protected EnumSet<TemplateTypeEnum> getStyle() {
|
||||
return EnumSet.of(TemplateTypeEnum.THYMELEAF);
|
||||
}
|
||||
|
||||
private String applyTemplateWithinTag(ITemplateContext theTemplateContext, String theName, String theElement) {
|
||||
private String applyTemplateWithinTag(FhirContext theFhirContext, ITemplateContext theTemplateContext, String theName, String theElement) {
|
||||
IEngineConfiguration configuration = theTemplateContext.getConfiguration();
|
||||
IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(configuration);
|
||||
final IStandardExpression expression = expressionParser.parseExpression(theTemplateContext, theElement);
|
||||
|
@ -113,20 +109,20 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
return "";
|
||||
}
|
||||
|
||||
Optional<INarrativeTemplate> templateOpt;
|
||||
List<INarrativeTemplate> templateOpt;
|
||||
if (isNotBlank(theName)) {
|
||||
templateOpt = getManifest().getTemplateByName(getStyle(), theName);
|
||||
if (!templateOpt.isPresent()) {
|
||||
templateOpt = getManifest().getTemplateByName(theFhirContext, getStyle(), theName);
|
||||
if (templateOpt.isEmpty()) {
|
||||
throw new InternalErrorException("Unknown template name: " + theName);
|
||||
}
|
||||
} else {
|
||||
templateOpt = getManifest().getTemplateByElement(getStyle(), elementValue);
|
||||
if (!templateOpt.isPresent()) {
|
||||
templateOpt = getManifest().getTemplateByElement(theFhirContext, getStyle(), elementValue);
|
||||
if (templateOpt.isEmpty()) {
|
||||
throw new InternalErrorException("No template for type: " + elementValue.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
return applyTemplate(templateOpt.get(), elementValue);
|
||||
return applyTemplate(theFhirContext, templateOpt.get(0), elementValue);
|
||||
}
|
||||
|
||||
public void setMessageResolver(IMessageResolver theMessageResolver) {
|
||||
|
@ -135,9 +131,15 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
|
||||
|
||||
private class ProfileResourceResolver extends DefaultTemplateResolver {
|
||||
private final FhirContext myFhirContext;
|
||||
|
||||
private ProfileResourceResolver(FhirContext theFhirContext) {
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean computeResolvable(IEngineConfiguration theConfiguration, String theOwnerTemplate, String theTemplate, Map<String, Object> theTemplateResolutionAttributes) {
|
||||
return getManifest().getTemplateByName(getStyle(), theTemplate).isPresent();
|
||||
return getManifest().getTemplateByName(myFhirContext, getStyle(), theTemplate).size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -148,7 +150,9 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
@Override
|
||||
protected ITemplateResource computeTemplateResource(IEngineConfiguration theConfiguration, String theOwnerTemplate, String theTemplate, Map<String, Object> theTemplateResolutionAttributes) {
|
||||
return getManifest()
|
||||
.getTemplateByName(getStyle(), theTemplate)
|
||||
.getTemplateByName(myFhirContext, getStyle(), theTemplate)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(t -> new StringTemplateResource(t.getTemplateText()))
|
||||
.orElseThrow(() -> new IllegalArgumentException("Unknown template: " + theTemplate));
|
||||
}
|
||||
|
@ -161,8 +165,11 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
|
||||
private class NarrativeTagProcessor extends AbstractElementTagProcessor {
|
||||
|
||||
public NarrativeTagProcessor(String dialectPrefix) {
|
||||
private final FhirContext myFhirContext;
|
||||
|
||||
NarrativeTagProcessor(FhirContext theFhirContext, String dialectPrefix) {
|
||||
super(TemplateMode.XML, dialectPrefix, "narrative", true, null, true, 0);
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -170,7 +177,7 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
String name = theTag.getAttributeValue("th:name");
|
||||
String element = theTag.getAttributeValue("th:element");
|
||||
|
||||
String appliedTemplate = applyTemplateWithinTag(theTemplateContext, name, element);
|
||||
String appliedTemplate = applyTemplateWithinTag(myFhirContext, theTemplateContext, name, element);
|
||||
theStructureHandler.replaceWith(appliedTemplate, false);
|
||||
}
|
||||
}
|
||||
|
@ -181,13 +188,16 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
|
|||
*/
|
||||
private class NarrativeAttributeProcessor extends AbstractAttributeTagProcessor {
|
||||
|
||||
protected NarrativeAttributeProcessor(String theDialectPrefix) {
|
||||
private final FhirContext myFhirContext;
|
||||
|
||||
NarrativeAttributeProcessor(String theDialectPrefix, FhirContext theFhirContext) {
|
||||
super(TemplateMode.XML, theDialectPrefix, null, false, "narrative", true, 0, true);
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doProcess(ITemplateContext theContext, IProcessableElementTag theTag, AttributeName theAttributeName, String theAttributeValue, IElementTagStructureHandler theStructureHandler) {
|
||||
String text = applyTemplateWithinTag(theContext, null, theAttributeValue);
|
||||
String text = applyTemplateWithinTag(myFhirContext, theContext, null, theAttributeValue);
|
||||
theStructureHandler.setBody(text, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
narr = null;
|
||||
}
|
||||
if (narr != null && narr.isEmpty()) {
|
||||
gen.populateResourceNarrative(theResource);
|
||||
gen.populateResourceNarrative(myContext, theResource);
|
||||
if (!narr.isEmpty()) {
|
||||
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
|
||||
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
|
||||
|
|
|
@ -371,7 +371,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
}
|
||||
// FIXME potential null access on narr see line 623
|
||||
if (gen != null && narr.isEmpty()) {
|
||||
gen.populateResourceNarrative(theResource);
|
||||
gen.populateResourceNarrative(myContext, theResource);
|
||||
}
|
||||
if (narr != null && narr.isEmpty() == false) {
|
||||
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
|
||||
|
|
|
@ -1241,7 +1241,7 @@ public class JsonParserDstu3Test {
|
|||
Patient p = new Patient();
|
||||
p.addName().setFamily("Smith").addGiven("John");
|
||||
|
||||
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator(ourCtx));
|
||||
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
String output = ourCtx.newJsonParser().encodeResourceToString(p);
|
||||
ourLog.info(output);
|
||||
|
@ -1410,7 +1410,7 @@ public class JsonParserDstu3Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidDateTimeValueInvalid() throws Exception {
|
||||
public void testInvalidDateTimeValueInvalid() {
|
||||
IParserErrorHandler errorHandler = mock(IParserErrorHandler.class);
|
||||
|
||||
String res = "{ \"resourceType\": \"Observation\", \"valueDateTime\": \"foo\" }";
|
||||
|
@ -1422,7 +1422,7 @@ public class JsonParserDstu3Test {
|
|||
assertEquals("foo", parsed.getValueDateTimeType().getValueAsString());
|
||||
|
||||
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
|
||||
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq("foo"), msgCaptor.capture());
|
||||
verify(errorHandler, times(1)).invalidValue(isNull(), eq("foo"), msgCaptor.capture());
|
||||
assertEquals("Invalid date/time format: \"foo\"", msgCaptor.getValue());
|
||||
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
|
||||
|
@ -1454,7 +1454,7 @@ public class JsonParserDstu3Test {
|
|||
assertEquals(null, parsed.getGenderElement().getValueAsString());
|
||||
|
||||
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
|
||||
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq(""), msgCaptor.capture());
|
||||
verify(errorHandler, times(1)).invalidValue(isNull(), eq(""), msgCaptor.capture());
|
||||
assertEquals("Attribute values must not be empty (\"\")", msgCaptor.getValue());
|
||||
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
|
||||
|
@ -1474,7 +1474,7 @@ public class JsonParserDstu3Test {
|
|||
assertEquals("foo", parsed.getGenderElement().getValueAsString());
|
||||
|
||||
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
|
||||
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq("foo"), msgCaptor.capture());
|
||||
verify(errorHandler, times(1)).invalidValue(isNull(), eq("foo"), msgCaptor.capture());
|
||||
assertEquals("Unknown AdministrativeGender code 'foo'", msgCaptor.getValue());
|
||||
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
|
||||
|
@ -1509,7 +1509,7 @@ public class JsonParserDstu3Test {
|
|||
// FIXME: this should pass
|
||||
@Test
|
||||
@Ignore
|
||||
public void testNamespacePreservationEncode() throws Exception {
|
||||
public void testNamespacePreservationEncode() {
|
||||
//@formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
|
||||
"<text>" +
|
||||
|
@ -1533,7 +1533,7 @@ public class JsonParserDstu3Test {
|
|||
// TODO: this should pass
|
||||
@Test
|
||||
@Ignore
|
||||
public void testNamespacePreservationParse() throws Exception {
|
||||
public void testNamespacePreservationParse() {
|
||||
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
|
||||
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
|
||||
XhtmlNode div = parsed.getText().getDiv();
|
||||
|
@ -2065,7 +2065,7 @@ public class JsonParserDstu3Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testParseMetadata() throws Exception {
|
||||
public void testParseMetadata() {
|
||||
//@formatter:off
|
||||
String bundle = "{\n" +
|
||||
" \"resourceType\" : \"Bundle\",\n" +
|
||||
|
@ -2219,7 +2219,7 @@ public class JsonParserDstu3Test {
|
|||
}
|
||||
|
||||
@Test(expected = DataFormatException.class)
|
||||
public void testParseWithTrailingContent() throws Exception {
|
||||
public void testParseWithTrailingContent() {
|
||||
//@formatter:off
|
||||
String bundle = "{\n" +
|
||||
" \"resourceType\" : \"Bundle\",\n" +
|
||||
|
|
|
@ -1943,7 +1943,7 @@ public class XmlParserDstu3Test {
|
|||
Patient p = new Patient();
|
||||
p.addName().setFamily("Smith").addGiven("John");
|
||||
|
||||
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator(ourCtx));
|
||||
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
String output = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
ourLog.info(output);
|
||||
|
|
Loading…
Reference in New Issue