package ca.uhn.fhir.jpa.dao.dstu3;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2017 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 static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.math.BigDecimal;
import java.util.*;
import javax.measure.unit.NonSI;
import javax.measure.unit.Unit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.dstu3.context.IWorkerContext;
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestSecurityComponent;
import org.hl7.fhir.dstu3.model.Enumeration;
import org.hl7.fhir.dstu3.model.Location.LocationPositionComponent;
import org.hl7.fhir.dstu3.model.Patient.PatientCommunicationComponent;
import org.hl7.fhir.dstu3.utils.FHIRPathEngine;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.annotations.VisibleForTesting;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implements ISearchParamExtractor {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamExtractorDstu3.class);
@Autowired
private org.hl7.fhir.dstu3.hapi.validation.IValidationSupport myValidationSupport;
/**
* Constructor
*/
public SearchParamExtractorDstu3() {
super();
}
public SearchParamExtractorDstu3(FhirContext theCtx, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry) {
super(theCtx, theSearchParamRegistry);
myValidationSupport = theValidationSupport;
}
private void addSearchTerm(ResourceTable theEntity, Set<ResourceIndexedSearchParamString> retVal, String resourceName, String searchTerm) {
if (isBlank(searchTerm)) {
return;
}
if (searchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
searchTerm = searchTerm.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
}
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseHapiFhirDao.normalizeString(searchTerm), searchTerm);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
private void addStringParam(ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> retVal, RuntimeSearchParam nextSpDef, String value) {
if (value.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
value = value.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
}
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), BaseHapiFhirDao.normalizeString(value), value);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
@Override
public Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
// TODO: implement
return Collections.emptySet();
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
*/
@Override
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IBaseResource theResource) {
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<ResourceIndexedSearchParamDate>();
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
for (RuntimeSearchParam nextSpDef : searchParams) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.DATE) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null) {
continue;
}
ResourceIndexedSearchParamDate nextEntity;
if (nextObject instanceof BaseDateTimeType) {
BaseDateTimeType nextValue = (BaseDateTimeType) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), nextValue.getValue(), nextValue.getValue());
} else if (nextObject instanceof Period) {
Period nextValue = (Period) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), nextValue.getStart(), nextValue.getEnd());
} else if (nextObject instanceof Timing) {
Timing nextValue = (Timing) nextObject;
if (nextValue.isEmpty()) {
continue;
}
TreeSet<Date> dates = new TreeSet<Date>();
for (DateTimeType nextEvent : nextValue.getEvent()) {
if (nextEvent.getValue() != null) {
dates.add(nextEvent.getValue());
}
}
if (dates.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), dates.first(), dates.last());
} else if (nextObject instanceof StringType) {
// CarePlan.activitydate can be a string
continue;
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
if (nextEntity != null) {
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
}
}
return retVal;
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
*/
@Override
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IBaseResource theResource) {
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<ResourceIndexedSearchParamNumber>();
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
for (RuntimeSearchParam nextSpDef : searchParams) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.NUMBER) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
continue;
}
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof Duration) {
Duration nextValue = (Duration) nextObject;
if (nextValue.getValueElement().isEmpty()) {
continue;
}
if (BaseHapiFhirDao.UCUM_NS.equals(nextValue.getSystem())) {
if (isNotBlank(nextValue.getCode())) {
Unit<? extends javax.measure.quantity.Quantity> unit = Unit.valueOf(nextValue.getCode());
javax.measure.converter.UnitConverter dayConverter = unit.getConverterTo(NonSI.DAY);
double dayValue = dayConverter.convert(nextValue.getValue().doubleValue());
Duration newValue = new Duration();
newValue.setSystem(BaseHapiFhirDao.UCUM_NS);
newValue.setCode(NonSI.DAY.toString());
newValue.setValue(dayValue);
nextValue = newValue;
/*
* @SuppressWarnings("unchecked") PhysicsUnit<? extends org.unitsofmeasurement.quantity.Quantity<?>> unit = (PhysicsUnit<? extends org.unitsofmeasurement.quantity.Quantity<?>>)
* UCUMFormat.getCaseInsensitiveInstance().parse(nextValue.getCode().getValue(), null); if (unit.isCompatible(UCUM.DAY)) {
*
* @SuppressWarnings("unchecked") PhysicsUnit<org.unitsofmeasurement.quantity.Time> timeUnit = (PhysicsUnit<Time>) unit; UnitConverter conv = timeUnit.getConverterTo(UCUM.DAY);
* double dayValue = conv.convert(nextValue.getValue().getValue().doubleValue()); Duration newValue = new Duration(); newValue.setSystem(UCUM_NS);
* newValue.setCode(UCUM.DAY.getSymbol()); newValue.setValue(dayValue); nextValue=newValue; }
*/
}
}
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else if (nextObject instanceof Quantity) {
Quantity nextValue = (Quantity) nextObject;
if (nextValue.getValueElement().isEmpty()) {
continue;
}
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else if (nextObject instanceof IntegerType) {
IntegerType nextValue = (IntegerType) nextObject;
if (nextValue.getValue() == null) {
continue;
}
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, new BigDecimal(nextValue.getValue()));
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
}
return retVal;
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
*/
@Override
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IBaseResource theResource) {
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<ResourceIndexedSearchParamQuantity>();
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
for (RuntimeSearchParam nextSpDef : searchParams) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.QUANTITY) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
continue;
}
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof Quantity) {
Quantity nextValue = (Quantity) nextObject;
addQuantity(theEntity, retVal, resourceName, nextValue);
} else if (nextObject instanceof Range) {
Range nextValue = (Range)nextObject;
addQuantity(theEntity, retVal, resourceName, nextValue.getLow());
addQuantity(theEntity, retVal, resourceName, nextValue.getHigh());
} else if (nextObject instanceof LocationPositionComponent) {
continue;
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
}
return retVal;
}
private void addQuantity(ResourceTable theEntity, HashSet<ResourceIndexedSearchParamQuantity> retVal, String resourceName, Quantity nextValue) {
if (!nextValue.getValueElement().isEmpty()) {
BigDecimal nextValueValue = nextValue.getValueElement().getValue();
String nextValueString = nextValue.getSystemElement().getValueAsString();
String nextValueCode = nextValue.getCode();
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValueValue, nextValueString, nextValueCode);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
*/
@Override
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IBaseResource theResource) {
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
String resourceName = getContext().getResourceDefinition(theResource).getName();
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
for (RuntimeSearchParam nextSpDef : searchParams) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.STRING) {
continue;
}
String nextPath = nextSpDef.getPath();
String nextSpName = nextSpDef.getName();
if (isBlank(nextPath)) {
// // TODO: implement phonetic, and any others that have no path
//
// // TODO: do we still need this check?
// if ("Questionnaire".equals(nextSpName) && nextSpDef.getName().equals("title")) {
// Questionnaire q = (Questionnaire) theResource;
// String title = "";// q.getGroup().getTitle();
// addSearchTerm(theEntity, retVal, nextSpName, title);
// }
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
continue;
}
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof IPrimitiveType<?>) {
IPrimitiveType<?> nextValue = (IPrimitiveType<?>) nextObject;
String searchTerm = nextValue.getValueAsString();
addSearchTerm(theEntity, retVal, nextSpName, searchTerm);
} else {
if (nextObject instanceof HumanName) {
ArrayList<StringType> allNames = new ArrayList<StringType>();
HumanName nextHumanName = (HumanName) nextObject;
if (isNotBlank(nextHumanName.getFamily())) {
allNames.add(nextHumanName.getFamilyElement());
}
allNames.addAll(nextHumanName.getGiven());
for (StringType nextName : allNames) {
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
}
} else if (nextObject instanceof Address) {
ArrayList<StringType> allNames = new ArrayList<StringType>();
Address nextAddress = (Address) nextObject;
allNames.addAll(nextAddress.getLine());
allNames.add(nextAddress.getCityElement());
allNames.add(nextAddress.getStateElement());
allNames.add(nextAddress.getCountryElement());
allNames.add(nextAddress.getPostalCodeElement());
for (StringType nextName : allNames) {
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
}
} else if (nextObject instanceof ContactPoint) {
ContactPoint nextContact = (ContactPoint) nextObject;
if (nextContact.getValueElement().isEmpty() == false) {
addSearchTerm(theEntity, retVal, nextSpName, nextContact.getValue());
}
} else if (nextObject instanceof Quantity) {
BigDecimal value = ((Quantity) nextObject).getValue();
if (value != null) {
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
}
} else if (nextObject instanceof Range) {
SimpleQuantity low = ((Range) nextObject).getLow();
if (low != null) {
BigDecimal value = low.getValue();
if (value != null) {
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
}
}
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpName + " is of unexpected datatype: " + nextObject.getClass());
}
}
}
}
}
return retVal;
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
*/
@Override
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IBaseResource theResource) {
HashSet<BaseResourceIndexedSearchParam> retVal = new HashSet<BaseResourceIndexedSearchParam>();
String useSystem = null;
if (theResource instanceof CodeSystem) {
CodeSystem cs = (CodeSystem) theResource;
useSystem = cs.getUrl();
}
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
for (RuntimeSearchParam nextSpDef : searchParams) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
List<String> systems = new ArrayList<String>();
List<String> codes = new ArrayList<String>();
// String needContactPointSystem = null;
// if (nextPath.contains(".where(system='phone')")) {
// nextPath = nextPath.replace(".where(system='phone')", "");
// needContactPointSystem = "phone";
// }
// if (nextPath.contains(".where(system='email')")) {
// nextPath = nextPath.replace(".where(system='email')", "");
// needContactPointSystem = "email";
// }
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject instanceof Extension) {
Extension nextExtension = (Extension)nextObject;
nextObject = nextExtension.getValue();
}
if (nextObject == null) {
continue;
}
// Patient:language
if (nextObject instanceof PatientCommunicationComponent) {
PatientCommunicationComponent nextValue = (PatientCommunicationComponent) nextObject;
nextObject = nextValue.getLanguage();
}
if (nextObject instanceof Identifier) {
Identifier nextValue = (Identifier) nextObject;
if (nextValue.isEmpty()) {
continue;
}
String system = StringUtils.defaultIfBlank(nextValue.getSystemElement().getValueAsString(), null);
String value = nextValue.getValueElement().getValue();
if (isNotBlank(value)) {
systems.add(system);
codes.add(value);
}
if (isNotBlank(nextValue.getType().getText())) {
addStringParam(theEntity, retVal, nextSpDef, nextValue.getType().getText());
}
} else if (nextObject instanceof ContactPoint) {
ContactPoint nextValue = (ContactPoint) nextObject;
if (nextValue.isEmpty()) {
continue;
}
systems.add(nextValue.getSystemElement().getValueAsString());
codes.add(nextValue.getValueElement().getValue());
} else if (nextObject instanceof Enumeration<?>) {
Enumeration<?> obj = (Enumeration<?>) nextObject;
String system = extractSystem(obj);
String code = obj.getValueAsString();
if (isNotBlank(code)) {
systems.add(system);
codes.add(code);
}
} else if (nextObject instanceof IPrimitiveType<?>) {
IPrimitiveType<?> nextValue = (IPrimitiveType<?>) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if ("CodeSystem.concept.code".equals(nextPath)) {
systems.add(useSystem);
} else {
systems.add(null);
}
codes.add(nextValue.getValueAsString());
} else if (nextObject instanceof Coding) {
Coding nextValue = (Coding) nextObject;
extractTokensFromCoding(systems, codes, theEntity, retVal, nextSpDef, nextValue);
} else if (nextObject instanceof CodeableConcept) {
CodeableConcept nextCC = (CodeableConcept) nextObject;
if (!nextCC.getTextElement().isEmpty()) {
addStringParam(theEntity, retVal, nextSpDef, nextCC.getTextElement().getValue());
}
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
} else if (nextObject instanceof CapabilityStatementRestSecurityComponent) {
// Conformance.security search param points to something kind of useless right now - This should probably
// be fixed.
CapabilityStatementRestSecurityComponent sec = (CapabilityStatementRestSecurityComponent) nextObject;
for (CodeableConcept nextCC : sec.getService()) {
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
}
} else if (nextObject instanceof LocationPositionComponent) {
ourLog.warn("Position search not currently supported, not indexing location");
continue;
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
assert systems.size() == codes.size() : "Systems contains " + systems + ", codes contains: " + codes;
Set<Pair<String, String>> haveValues = new HashSet<Pair<String, String>>();
for (int i = 0; i < systems.size(); i++) {
String system = systems.get(i);
String code = codes.get(i);
if (isBlank(system) && isBlank(code)) {
continue;
}
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
system = system.substring(0, ResourceIndexedSearchParamToken.MAX_LENGTH);
}
if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
code = code.substring(0, ResourceIndexedSearchParamToken.MAX_LENGTH);
}
Pair<String, String> nextPair = Pair.of(system, code);
if (haveValues.contains(nextPair)) {
continue;
}
haveValues.add(nextPair);
ResourceIndexedSearchParamToken nextEntity;
nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), system, code);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
}
return retVal;
}
@Override
public Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource) {
HashSet<ResourceIndexedSearchParamUri> retVal = new HashSet<ResourceIndexedSearchParamUri>();
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
for (RuntimeSearchParam nextSpDef : searchParams) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.URI) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
continue;
}
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof UriType) {
UriType nextValue = (UriType) nextObject;
if (isBlank(nextValue.getValue())) {
continue;
}
ourLog.trace("Adding param: {}, {}", resourceName, nextValue.getValue());
ResourceIndexedSearchParamUri nextEntity = new ResourceIndexedSearchParamUri(resourceName, nextValue.getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
}
return retVal;
}
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConcept theCodeableConcept, ResourceTable theEntity,
Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
for (Coding nextCoding : theCodeableConcept.getCoding()) {
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
}
}
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate,
RuntimeSearchParam theParameterDef, Coding nextCoding) {
if (nextCoding != null && !nextCoding.isEmpty()) {
String nextSystem = nextCoding.getSystemElement().getValueAsString();
String nextCode = nextCoding.getCodeElement().getValue();
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
theSystems.add(nextSystem);
theCodes.add(nextCode);
}
if (!nextCoding.getDisplayElement().isEmpty()) {
addStringParam(theEntity, theListToPopulate, theParameterDef, nextCoding.getDisplayElement().getValue());
}
}
}
/**
* Override parent because we're using FHIRPath here
*/
@Override
protected List<Object> extractValues(String thePaths, IBaseResource theResource) {
IWorkerContext worker = new org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext(getContext(), myValidationSupport);
FHIRPathEngine fp = new FHIRPathEngine(worker);
List<Object> values = new ArrayList<Object>();
try {
String[] nextPathsSplit = SPLIT.split(thePaths);
for (String nextPath : nextPathsSplit) {
List<Base> allValues = fp.evaluate((Base) theResource, nextPath);
if (allValues.isEmpty() == false) {
values.addAll(allValues);
}
}
} catch (FHIRException e) {
throw new InternalErrorException(e);
}
return values;
}
@Override
public List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef) {
ArrayList<PathAndRef> retVal = new ArrayList<PathAndRef>();
String[] nextPathsSplit = SPLIT.split(theNextSpDef.getPath());
for (String path : nextPathsSplit) {
path = path.trim();
if (isNotBlank(path)) {
for (Object next : extractValues(path, theResource)) {
retVal.add(new PathAndRef(path, next));
}
}
}
return retVal;
}
@VisibleForTesting
void setValidationSupportForTesting(org.hl7.fhir.dstu3.hapi.validation.IValidationSupport theValidationSupport) {
myValidationSupport = theValidationSupport;
}
private static <T extends Enum<?>> String extractSystem(Enumeration<T> theBoundCode) {
if (theBoundCode.getValue() != null) {
return theBoundCode.getEnumFactory().toSystem(theBoundCode.getValue());
}
return null;
}
}