Work on getting tests passing

This commit is contained in:
James Agnew 2016-05-02 11:42:55 -04:00
parent c90795ccef
commit 804149205a
17 changed files with 386 additions and 188 deletions

View File

@ -769,7 +769,7 @@ class ModelScanner {
}
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments);
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments, toTargetList(searchParam.target()));
theResourceDef.addSearchParam(param);
nameToParam.put(param.getName(), param);
}
@ -789,11 +789,24 @@ class ModelScanner {
compositeOf.add(param);
}
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), RestSearchParameterTypeEnum.COMPOSITE, compositeOf, null);
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), RestSearchParameterTypeEnum.COMPOSITE, compositeOf, null, toTargetList(searchParam.target()));
theResourceDef.addSearchParam(param);
}
}
private Set<String> toTargetList(Class<? extends IBaseResource>[] theTarget) {
HashSet<String> retVal = new HashSet<String>();
for (Class<? extends IBaseResource> nextType : theTarget) {
ResourceDef resourceDef = nextType.getAnnotation(ResourceDef.class);
if (resourceDef != null) {
retVal.add(resourceDef.name());
}
}
return retVal;
}
private static Class<?> getGenericCollectionTypeOfCodedField(Field next) {
Class<?> type;
ParameterizedType collectionType = (ParameterizedType) next.getGenericType();

View File

@ -30,15 +30,16 @@ import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
public class RuntimeSearchParam {
private List<RuntimeSearchParam> myCompositeOf;
private String myDescription;
private String myName;
private RestSearchParameterTypeEnum myParamType;
private String myPath;
private Set<String> myProvidesMembershipInCompartments;
private final List<RuntimeSearchParam> myCompositeOf;
private final String myDescription;
private final String myName;
private final RestSearchParameterTypeEnum myParamType;
private final String myPath;
private final Set<String> myTargets;
private final Set<String> myProvidesMembershipInCompartments;
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, List<RuntimeSearchParam> theCompositeOf,
Set<String> theProvidesMembershipInCompartments) {
Set<String> theProvidesMembershipInCompartments, Set<String> theTargets) {
super();
myName = theName;
myDescription = theDescription;
@ -50,10 +51,19 @@ public class RuntimeSearchParam {
} else {
myProvidesMembershipInCompartments = null;
}
if (theTargets != null && theTargets.isEmpty() == false) {
myTargets = Collections.unmodifiableSet(theTargets);
} else {
myTargets = null;
}
}
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set<String> theProvidesMembershipInCompartments) {
this(theName, theDescription, thePath, theParamType, null, theProvidesMembershipInCompartments);
public Set<String> getTargets() {
return myTargets;
}
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set<String> theProvidesMembershipInCompartments, Set<String> theTargets) {
this(theName, theDescription, thePath, theParamType, null, theProvidesMembershipInCompartments, theTargets);
}
public List<RuntimeSearchParam> getCompositeOf() {

View File

@ -1,5 +1,8 @@
package ca.uhn.fhir.cli;
import java.util.Collections;
import java.util.List;
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.StructureDefinition;
@ -61,4 +64,9 @@ public class LoadingValidationSupportDstu3 implements IValidationSupport {
return null;
}
@Override
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
return Collections.emptyList();
}
}

View File

@ -45,7 +45,6 @@ import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.xml.stream.events.Characters;
@ -60,6 +59,7 @@ import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseReference;
@ -74,6 +74,8 @@ import com.google.common.base.Charsets;
import com.google.common.collect.ArrayListMultimap;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
@ -84,7 +86,6 @@ import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.BaseTag;
@ -224,7 +225,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
if (isValidPid(theId)) {
return;
}
ForcedId fid = new ForcedId();
fid.setResourceType(theEntity.getResourceType());
fid.setForcedId(theId.getIdPart());
@ -259,121 +260,121 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
multiType = true;
}
String[] nextPathsSplit = nextPathsUnsplit.split("\\|");
for (String nextPath : nextPathsSplit) {
nextPath = nextPath.trim();
List<PathAndRef> refs = mySearchParamExtractor.extractResourceLinks(theResource, nextSpDef);
List<Class<? extends IBaseResource>> allowedTypesInField = null;
for (PathAndRef nextPathAndRef : refs) {
Object nextObject = nextPathAndRef.getRef();
List<Class<? extends IBaseResource>> allowedTypesInField = null;
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null) {
ResourceLink nextEntity;
if (nextObject instanceof IBaseReference) {
IBaseReference nextValue = (IBaseReference) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if (nextValue.getReferenceElement().isEmpty() || nextValue.getReferenceElement().getValue().startsWith("#")) {
// This is a blank or contained resource reference
continue;
}
ResourceLink nextEntity;
if (nextObject instanceof IBaseReference) {
IBaseReference nextValue = (IBaseReference) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if (nextValue.getReferenceElement().isEmpty() || nextValue.getReferenceElement().getValue().startsWith("#")) {
// This is a blank or contained resource reference
continue;
}
String typeString = nextValue.getReferenceElement().getResourceType();
if (isBlank(typeString)) {
throw new InvalidRequestException(
"Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextValue.getReferenceElement().getValue());
}
RuntimeResourceDefinition resourceDefinition;
try {
resourceDefinition = getContext().getResourceDefinition(typeString);
} catch (DataFormatException e) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Resource type is unknown or not supported on this server - "
+ nextValue.getReferenceElement().getValue());
}
Class<? extends IBaseResource> type = resourceDefinition.getImplementingClass();
String id = nextValue.getReferenceElement().getIdPart();
if (StringUtils.isBlank(id)) {
throw new InvalidRequestException(
"Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource ID - " + nextValue.getReferenceElement().getValue());
}
IFhirResourceDao<?> dao = getDao(type);
if (dao == null) {
StringBuilder b = new StringBuilder();
b.append("This server (version ");
b.append(myContext.getVersion().getVersion());
b.append(") is not able to handle resources of type[");
b.append(nextValue.getReferenceElement().getResourceType());
b.append("] - Valid resource types for this server: ");
b.append(myResourceTypeToDao.keySet().toString());
throw new InvalidRequestException(b.toString());
}
Long valueOf;
try {
valueOf = translateForcedIdToPid(typeString, id);
} catch (ResourceNotFoundException e) {
String resName = getContext().getResourceDefinition(type).getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
ResourceTable target = myEntityManager.find(ResourceTable.class, valueOf);
RuntimeResourceDefinition targetResourceDef = getContext().getResourceDefinition(type);
if (target == null) {
String resName = targetResourceDef.getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
if (!typeString.equals(target.getResourceType())) {
throw new UnprocessableEntityException("Resource contains reference to " + nextValue.getReferenceElement().getValue() + " but resource with ID "
+ nextValue.getReferenceElement().getIdPart() + " is actually of type " + target.getResourceType());
}
/*
* Is the target type an allowable type of resource for the path where it is referenced?
*/
if (allowedTypesInField == null) {
BaseRuntimeChildDefinition childDef = getContext().newTerser().getDefinition(theResource.getClass(), nextPath);
if (childDef instanceof RuntimeChildResourceDefinition) {
RuntimeChildResourceDefinition resRefDef = (RuntimeChildResourceDefinition) childDef;
allowedTypesInField = resRefDef.getResourceTypes();
} else {
allowedTypesInField = new ArrayList<Class<? extends IBaseResource>>();
allowedTypesInField.add(IBaseResource.class);
}
}
boolean acceptableLink = false;
for (Class<? extends IBaseResource> next : allowedTypesInField) {
if (next.isAssignableFrom(targetResourceDef.getImplementingClass())) {
acceptableLink = true;
break;
}
}
if (!acceptableLink) {
throw new UnprocessableEntityException("Invalid reference found at path '" + nextPath + "'. Resource type '" + targetResourceDef.getName() + "' is not valid for this path");
}
nextEntity = new ResourceLink(nextPath, theEntity, target);
} else {
if (!multiType) {
if (nextSpDef.getName().equals("sourceuri")) {
continue; // TODO: disable this eventually - ConceptMap:sourceuri is of type reference but points to a URI
}
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
String typeString = nextValue.getReferenceElement().getResourceType();
if (isBlank(typeString)) {
throw new InvalidRequestException(
"Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextValue.getReferenceElement().getValue());
}
if (nextEntity != null) {
retVal.add(nextEntity);
RuntimeResourceDefinition resourceDefinition;
try {
resourceDefinition = getContext().getResourceDefinition(typeString);
} catch (DataFormatException e) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Resource type is unknown or not supported on this server - "
+ nextValue.getReferenceElement().getValue());
}
Class<? extends IBaseResource> type = resourceDefinition.getImplementingClass();
String id = nextValue.getReferenceElement().getIdPart();
if (StringUtils.isBlank(id)) {
throw new InvalidRequestException(
"Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource ID - " + nextValue.getReferenceElement().getValue());
}
IFhirResourceDao<?> dao = getDao(type);
if (dao == null) {
StringBuilder b = new StringBuilder();
b.append("This server (version ");
b.append(myContext.getVersion().getVersion());
b.append(") is not able to handle resources of type[");
b.append(nextValue.getReferenceElement().getResourceType());
b.append("] - Valid resource types for this server: ");
b.append(myResourceTypeToDao.keySet().toString());
throw new InvalidRequestException(b.toString());
}
Long valueOf;
try {
valueOf = translateForcedIdToPid(typeString, id);
} catch (ResourceNotFoundException e) {
String resName = getContext().getResourceDefinition(type).getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
ResourceTable target = myEntityManager.find(ResourceTable.class, valueOf);
RuntimeResourceDefinition targetResourceDef = getContext().getResourceDefinition(type);
if (target == null) {
String resName = targetResourceDef.getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
if (!typeString.equals(target.getResourceType())) {
throw new UnprocessableEntityException("Resource contains reference to " + nextValue.getReferenceElement().getValue() + " but resource with ID "
+ nextValue.getReferenceElement().getIdPart() + " is actually of type " + target.getResourceType());
}
if (nextSpDef.getTargets() != null && !nextSpDef.getTargets().contains(typeString)) {
continue;
}
// /*
// * Is the target type an allowable type of resource for the path where it is referenced?
// */
//
// if (allowedTypesInField == null) {
// BaseRuntimeChildDefinition childDef = getContext().newTerser().getDefinition(theResource.getClass(), nextPathAndRef.getPath());
// if (childDef instanceof RuntimeChildResourceDefinition) {
// RuntimeChildResourceDefinition resRefDef = (RuntimeChildResourceDefinition) childDef;
// allowedTypesInField = resRefDef.getResourceTypes();
// } else {
// allowedTypesInField = new ArrayList<Class<? extends IBaseResource>>();
// allowedTypesInField.add(IBaseResource.class);
// }
// }
//
// boolean acceptableLink = false;
// for (Class<? extends IBaseResource> next : allowedTypesInField) {
// if (next.isAssignableFrom(targetResourceDef.getImplementingClass())) {
// acceptableLink = true;
// break;
// }
// }
//
// if (!acceptableLink) {
// throw new UnprocessableEntityException(
// "Invalid reference found at path '" + nextPathAndRef.getPath() + "'. Resource type '" + targetResourceDef.getName() + "' is not valid for this path");
// }
nextEntity = new ResourceLink(nextPathAndRef.getPath(), theEntity, target);
} else {
if (!multiType) {
if (nextSpDef.getName().equals("sourceuri")) {
continue; // TODO: disable this eventually - ConceptMap:sourceuri is of type reference but points to a URI
}
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
if (nextEntity != null) {
retVal.add(nextEntity);
}
}
}
theEntity.setHasLinks(retVal.size() > 0);
@ -518,7 +519,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return myConfig;
}
@Override
public FhirContext getContext() {
return myContext;
@ -655,7 +655,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
search.setTotalCount(myResourceHistoryTableDao.countForResourceInstance(theId));
}
}
search = mySearchDao.save(search);
return new PersistedJpaBundleProvider(search.getUuid(), this);
@ -679,7 +679,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
requestDetails.notifyIncomingRequestPreHandled(theOperationType);
List<IServerInterceptor> interceptors = getConfig().getInterceptors();
if (interceptors == null) {
return;
@ -877,7 +877,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
IDao.RESOURCE_PID.put(res, theEntity.getId());
Collection<? extends BaseTag> tags = theEntity.getTags();
if (theEntity.isHasTags()) {
for (BaseTag next : tags) {
switch (next.getTag().getTagType()) {
@ -977,7 +977,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
myContext = theContext;
}
public void setEntityManager(EntityManager theEntityManager) {
myEntityManager = theEntityManager;
}
@ -1458,6 +1457,63 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
if (tag != null) {
throw new UnprocessableEntityException("Resource contains the 'subsetted' tag, and must not be stored as it may contain a subset of available data");
}
String resName = getContext().getResourceDefinition(theResource).getName();
validateChildReferences(theResource, resName);
}
private void validateChildReferences(IBase theElement, String thePath) {
if (theElement == null) {
return;
}
BaseRuntimeElementDefinition<?> def = myContext.getElementDefinition(theElement.getClass());
if (!(def instanceof BaseRuntimeElementCompositeDefinition)) {
return;
}
BaseRuntimeElementCompositeDefinition<?> cdef = (BaseRuntimeElementCompositeDefinition<?>)def;
for (BaseRuntimeChildDefinition nextChildDef : cdef.getChildren()) {
List<IBase> values = nextChildDef.getAccessor().getValues(theElement);
if (values == null || values.isEmpty()) {
continue;
}
String newPath = thePath + "." + nextChildDef.getElementName();
for (IBase nextChild : values) {
validateChildReferences(nextChild, newPath);
}
if (nextChildDef instanceof RuntimeChildResourceDefinition) {
RuntimeChildResourceDefinition nextChildDefRes = (RuntimeChildResourceDefinition)nextChildDef;
Set<String> validTypes = new HashSet<String>();
boolean allowAny = false;
for (Class<? extends IBaseResource> nextValidType : nextChildDefRes.getResourceTypes()) {
if (nextValidType.isInterface()) {
allowAny = true;
break;
}
validTypes.add(getContext().getResourceDefinition(nextValidType).getName());
}
if (allowAny) {
continue;
}
for (IBase nextChild : values) {
IBaseReference nextRef = (IBaseReference)nextChild;
if (!isBlank(nextRef.getReferenceElement().getResourceType())) {
if (!validTypes.contains(nextRef.getReferenceElement().getResourceType())) {
throw new UnprocessableEntityException(
"Invalid reference found at path '" + newPath + "'. Resource type '" + nextRef.getReferenceElement().getResourceType() + "' is not valid for this path");
}
}
}
}
}
}
protected static boolean isValidPid(IIdType theId) {
@ -1561,7 +1617,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
static List<Long> translateForcedIdToPids(IIdType theId, IForcedIdDao theForcedIdDao) {
Validate.isTrue(theId.hasIdPart());
if (isValidPid(theId)) {
return Collections.singletonList(theId.getIdPartAsLong());
} else {
@ -1571,7 +1627,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
} else {
forcedId = theForcedIdDao.findByForcedId(theId.getIdPart());
}
if (forcedId.isEmpty() == false) {
List<Long> retVal = new ArrayList<Long>(forcedId.size());
for (ForcedId next : forcedId) {

View File

@ -31,12 +31,13 @@ import com.google.common.annotations.VisibleForTesting;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.util.FhirTerser;
public class BaseSearchParamExtractor {
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
private static final Pattern SPLIT = Pattern.compile("\\||( or )");
protected static final Pattern SPLIT = Pattern.compile("\\||( or )");
@Autowired
private FhirContext myContext;
@ -74,5 +75,21 @@ public class BaseSearchParamExtractor {
myContext = theContext;
}
@Override
public List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef) {
List<PathAndRef> refs = new ArrayList<PathAndRef>();
String[] nextPathsSplit = theNextSpDef.getPath().split("\\|");
for (String nextPath : nextPathsSplit) {
nextPath = nextPath.trim();
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null) {
continue;
}
refs.add(new PathAndRef(nextPath, nextObject));
}
}
return refs;
}
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.jpa.dao;
import java.util.List;
/*
* #%L
* HAPI FHIR JPA Server
@ -24,6 +26,7 @@ import java.util.Set;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
@ -49,4 +52,6 @@ public interface ISearchParamExtractor {
public abstract Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource);
public abstract List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef);
}

View File

@ -0,0 +1,19 @@
package ca.uhn.fhir.jpa.dao;
public class PathAndRef {
private final String myPath;
public String getPath() {
return myPath;
}
public PathAndRef(String thePath, Object theRef) {
super();
myPath = thePath;
myRef = theRef;
}
public Object getRef() {
return myRef;
}
private final Object myRef;
}

View File

@ -73,6 +73,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.BaseSearchParamExtractor;
import ca.uhn.fhir.jpa.dao.ISearchParamExtractor;
import ca.uhn.fhir.jpa.dao.PathAndRef;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
@ -88,17 +89,17 @@ 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) {
super(theCtx);
myValidationSupport = theValidationSupport;
@ -135,8 +136,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IBaseResource)
* @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) {
@ -196,8 +196,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IBaseResource)
* @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) {
@ -244,17 +243,12 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
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<? 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; }
* @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; }
*/
}
}
@ -296,8 +290,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IBaseResource)
* @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) {
@ -331,7 +324,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
continue;
}
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValue.getValueElement().getValue(), nextValue.getSystemElement().getValueAsString(), nextValue.getCode());
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValue.getValueElement().getValue(),
nextValue.getSystemElement().getValueAsString(), nextValue.getCode());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else {
@ -350,8 +344,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IBaseResource)
* @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) {
@ -372,7 +365,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
if ("Questionnaire".equals(def.getName()) && nextSpDef.getName().equals("title")) {
Questionnaire q = (Questionnaire) theResource;
String title = "";//q.getGroup().getTitle();
String title = "";// q.getGroup().getTitle();
addSearchTerm(theEntity, retVal, resourceName, title);
}
continue;
@ -432,8 +425,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IBaseResource)
* @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) {
@ -464,15 +456,15 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
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";
// }
// 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)) {
@ -639,14 +631,15 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
return retVal;
}
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConcept theCodeableConcept, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
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) {
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();
@ -670,16 +663,33 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
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>();
List<Object> values = new ArrayList<Object>();
try {
values.addAll(fp.evaluate((Base)theResource, thePaths));
values.addAll(fp.evaluate((Base) theResource, thePaths));
} 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;

View File

@ -83,7 +83,7 @@ public class FhirResourceDaoDstu1Test extends BaseJpaTest {
public void testCreateWithInvalidReferenceFailsGracefully() {
Patient patient = new Patient();
patient.addName().addFamily("testSearchResourceLinkWithChainWithMultipleTypes01");
patient.setManagingOrganization(new ResourceReferenceDt("Patient/99999999"));
patient.setManagingOrganization(new ResourceReferenceDt("Organization/99999999"));
try {
ourPatientDao.create(patient, mySrd);
fail();

View File

@ -593,7 +593,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
public void testCreateWithInvalidReferenceFailsGracefully() {
Patient patient = new Patient();
patient.addName().addFamily("testSearchResourceLinkWithChainWithMultipleTypes01");
patient.setManagingOrganization(new ResourceReferenceDt("Patient/99999999"));
patient.setManagingOrganization(new ResourceReferenceDt("Organization/99999999"));
try {
myPatientDao.create(patient, mySrd);
fail();
@ -626,8 +626,8 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
try {
myPatientDao.create(p, mySrd);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Invalid resource reference"));
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Invalid reference found at path 'Patient.managingOrganization'. Resource type 'Blah' is not valid for this path"));
}
}

View File

@ -278,7 +278,10 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
Class<ResourceIndexedSearchParamToken> type = ResourceIndexedSearchParamToken.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
// This is 3 for now because the FluentPath for Patient:deceased adds a value.. this should
// be corrected at some point, and we'll then drop back down to 2
assertEquals(3, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("http://foo1", "123")));
assertThat(actual, contains(id));

View File

@ -715,7 +715,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
public void testCreateWithInvalidReferenceFailsGracefully() {
Patient patient = new Patient();
patient.addName().addFamily("testSearchResourceLinkWithChainWithMultipleTypes01");
patient.setManagingOrganization(new Reference("Patient/99999999"));
patient.setManagingOrganization(new Reference("Organization/99999999"));
try {
myPatientDao.create(patient, mySrd);
fail();
@ -748,8 +748,8 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
try {
myPatientDao.create(p, mySrd);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Invalid resource reference"));
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Invalid reference found at path 'Patient.managingOrganization'. Resource type 'Blah' is not valid for this path"));
}
}

View File

@ -175,8 +175,8 @@ public class DynamicSearchTest {
@Override
public List<RuntimeSearchParam> getSearchParameters() {
ArrayList<RuntimeSearchParam> retVal = new ArrayList<RuntimeSearchParam>();
retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", RestSearchParameterTypeEnum.STRING, null));
retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", RestSearchParameterTypeEnum.DATE, null));
retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", RestSearchParameterTypeEnum.STRING, null, null));
retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", RestSearchParameterTypeEnum.DATE, null, null));
return retVal;
}

View File

@ -13,6 +13,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Claim;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Practitioner;
@ -23,11 +24,6 @@ public class ModelDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Test
public void testCompositeNames() {
assertEquals(MetaDt.class, ourCtx.getElementDefinition("meta").getImplementingClass());

View File

@ -50,6 +50,8 @@ import org.hl7.fhir.utilities.Table;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.ucum.Decimal;
import ca.uhn.fhir.util.ElementUtil;
/**
*
* @author Grahame Grieve
@ -2239,7 +2241,7 @@ public class FHIRPathEngine {
private List<Base> funcExists(ExecutionContext context, List<Base> focus, ExpressionNode exp) {
List<Base> result = new ArrayList<Base>();
result.add(new BooleanType(!focus.isEmpty()));
result.add(new BooleanType(!ElementUtil.isEmpty(focus)));
return result;
}
@ -2441,7 +2443,7 @@ public class FHIRPathEngine {
private List<Base> funcEmpty(ExecutionContext context, List<Base> focus, ExpressionNode exp) {
List<Base> result = new ArrayList<Base>();
result.add(new BooleanType(focus.isEmpty()));
result.add(new BooleanType(ElementUtil.isEmpty(focus)));
return result;
}

View File

@ -0,0 +1,54 @@
package org.hl7.fhir.dstu3.utils;
import static org.junit.Assert.*;
import java.util.List;
import org.hl7.fhir.dstu3.exceptions.FHIRException;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext;
import org.hl7.fhir.dstu3.model.Base;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.Patient;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
public class FhirPathEngineTest {
private static FhirContext ourCtx = FhirContext.forDstu3();
private static FHIRPathEngine ourEngine;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirPathEngineTest.class);
@Test
public void testExistsWithNoValue() throws FHIRException {
Patient patient = new Patient();
patient.setDeceased(new BooleanType());
List<Base> eval = ourEngine.evaluate(patient, "Patient.deceased.exists()");
ourLog.info(eval.toString());
assertFalse(((BooleanType)eval.get(0)).getValue());
}
@Test
public void testExistsWithValue() throws FHIRException {
Patient patient = new Patient();
patient.setDeceased(new BooleanType(false));
List<Base> eval = ourEngine.evaluate(patient, "Patient.deceased.exists()");
ourLog.info(eval.toString());
assertTrue(((BooleanType)eval.get(0)).getValue());
}
@AfterClass
public static void afterClassClearContext() throws Exception {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() {
ourEngine = new FHIRPathEngine(new HapiWorkerContext(ourCtx, new DefaultProfileValidationSupport()));
}
}

View File

@ -79,6 +79,11 @@
DSTU2 structures. Thanks to Rahul Somasunderam and
Claude Nanjo for the suggestions!
</action>
<action type="add">
JPA server has now been refactored to use the
new FluentPath search parameter definitions
for DSTU3 resources.
</action>
</release>
<release version="1.5" date="2016-04-20">
<action type="fix" issue="339">