Fix #212 - Dont accept invalid IDs but do accept IDs starting with a

number
This commit is contained in:
James Agnew 2015-08-28 15:36:56 -04:00
parent 4032a2674d
commit bd13b53099
14 changed files with 818 additions and 627 deletions

View File

@ -199,6 +199,34 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
return getIdPartAsBigDecimal();
}
private String determineLocalPrefix(String theValue) {
if (theValue == null || theValue.isEmpty()) {
return null;
}
if (theValue.startsWith("#")) {
return "#";
}
int lastPrefix = -1;
for (int i = 0; i < theValue.length(); i++) {
char nextChar = theValue.charAt(i);
if (nextChar == ':') {
lastPrefix = i;
} else if (!Character.isLetter(nextChar) || !Character.isLowerCase(nextChar)) {
break;
}
}
if (lastPrefix != -1) {
String candidate = theValue.substring(0, lastPrefix + 1);
if (candidate.startsWith("cid:") || candidate.startsWith("urn:")) {
return candidate;
} else {
return null;
}
} else {
return null;
}
}
@Override
public boolean equals(Object theArg0) {
if (!(theArg0 instanceof IdDt)) {
@ -383,6 +411,34 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
return isBlank(getValue());
}
@Override
public boolean isIdPartValid() {
String id = getIdPart();
if (StringUtils.isBlank(id)) {
return false;
}
if (id.length() > 64) {
return false;
}
for (int i = 0; i < id.length(); i++) {
char nextChar = id.charAt(i);
if (nextChar >= 'a' && nextChar <= 'z') {
continue;
}
if (nextChar >= 'A' && nextChar <= 'Z') {
continue;
}
if (nextChar >= '0' && nextChar <= '9') {
continue;
}
if (nextChar == '-' || nextChar == '.') {
continue;
}
return false;
}
return true;
}
/**
* Returns <code>true</code> if the unqualified ID is a valid {@link Long} value (in other words, it consists only of digits)
*/
@ -407,7 +463,7 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
public boolean isLocal() {
return "#".equals(myBaseUrl);
}
/**
* Copies the value from the given IdDt to <code>this</code> IdDt. It is generally not neccesary to use this method but it is provided for consistency with the rest of the API.
*/
@ -416,34 +472,6 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
setValue(theId.getValue());
}
private String determineLocalPrefix(String theValue) {
if (theValue == null || theValue.isEmpty()) {
return null;
}
if (theValue.startsWith("#")) {
return "#";
}
int lastPrefix = -1;
for (int i = 0; i < theValue.length(); i++) {
char nextChar = theValue.charAt(i);
if (nextChar == ':') {
lastPrefix = i;
} else if (!Character.isLetter(nextChar) || !Character.isLowerCase(nextChar)) {
break;
}
}
if (lastPrefix != -1) {
String candidate = theValue.substring(0, lastPrefix + 1);
if (candidate.startsWith("cid:") || candidate.startsWith("urn:")) {
return candidate;
} else {
return null;
}
} else {
return null;
}
}
/**
* Set the value
*
@ -602,6 +630,14 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
return new IdDt(value + '/' + Constants.PARAM_HISTORY + '/' + theVersion);
}
/**
* Construct a new ID with with form "urn:uuid:[UUID]" where [UUID] is a new, randomly
* created UUID generated by {@link UUID#randomUUID()}
*/
public static IdDt newRandomUuid() {
return new IdDt("urn:uuid:" + UUID.randomUUID().toString());
}
/**
* Retrieves the ID from the given resource instance
*/
@ -634,12 +670,4 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
return theIdPart.toString();
}
/**
* Construct a new ID with with form "urn:uuid:[UUID]" where [UUID] is a new, randomly
* created UUID generated by {@link UUID#randomUUID()}
*/
public static IdDt newRandomUuid() {
return new IdDt("urn:uuid:" + UUID.randomUUID().toString());
}
}

View File

@ -42,20 +42,22 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
}
/**
* Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a parameter
* Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a
* parameter
*
* @param theCodingDt
* The coding
* The coding
*/
public TokenParam(BaseCodingDt theCodingDt) {
this(toSystemValue(theCodingDt.getSystemElement()), theCodingDt.getCodeElement().getValue());
}
/**
* Constructor which copies the {@link BaseIdentifierDt#getSystemElement() system} and {@link BaseIdentifierDt#getValueElement() value} from a {@link BaseIdentifierDt} instance and adds it as a parameter
* Constructor which copies the {@link BaseIdentifierDt#getSystemElement() system} and {@link BaseIdentifierDt#getValueElement() value} from a {@link BaseIdentifierDt} instance and adds it as a
* parameter
*
* @param theIdentifierDt
* The identifier
* The identifier
*/
public TokenParam(BaseIdentifierDt theIdentifierDt) {
this(toSystemValue(theIdentifierDt.getSystemElement()), theIdentifierDt.getValueElement().getValue());
@ -102,12 +104,18 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
*/
@Override
void doSetValueAsQueryToken(String theQualifier, String theParameter) {
int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
if (barIndex != -1) {
setSystem(theParameter.substring(0, barIndex));
setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1)));
setText(Constants.PARAMQUALIFIER_TOKEN_TEXT.equals(theQualifier));
setSystem(null);
if (theParameter == null) {
setValue(null);
} else {
setValue(ParameterUtil.unescape(theParameter));
int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
if (barIndex != -1) {
setSystem(theParameter.substring(0, barIndex));
setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1)));
} else {
setValue(ParameterUtil.unescape(theParameter));
}
}
}

View File

@ -92,6 +92,19 @@ public interface IIdType {
*/
boolean isAbsolute();
/**
* Returns <code>true</code> if the {@link #getIdPart() ID part of this object} is valid according to the FHIR rules for valid IDs.
* <p>
* The FHIR specification states:
* <code>Any combination of upper or lower case ASCII letters ('A'..'Z', and 'a'..'z', numerals ('0'..'9'), '-' and '.', with a length limit of 64 characters. (This might be an integer, an un-prefixed OID, UUID or any other identifier pattern that meets these constraints.) regex: [A-Za-z0-9\-\.]{1,64}</code>
* </p>
*/
boolean isIdPartValid();
/**
* Returns <code>true</code> if the {@link #getIdPart() ID part of this object} contains
* only numbers
*/
boolean isIdPartValidLong();
Long getIdPartAsLong();

View File

@ -52,7 +52,8 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionMissingUrl=Unable to perfor
ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionInvalidUrl=Unable to perform {0}, URL provided is invalid: {1}
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.duplicateCreateForcedId=Can not create entity with ID[{0}], a resource with this ID already exists
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create resource with ID[{0}], no resource with this ID exists and clients may only assign IDs which begin with a non-numeric character on this server
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithInvalidId=Can not process entity with ID[{0}], this is not a valid FHIR ID
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create resource with ID[{0}], no resource with this ID exists and clients may only assign IDs which contain at least one non-numeric character
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedId=Can not create resource with ID[{0}], ID must not be supplied on a create (POST) operation
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidParameterChain=Invalid parameter chain: {0}
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true

View File

@ -18,7 +18,6 @@
<groupId>ca.uhn.hapi.example</groupId>
<artifactId>hapi-fhir-examples-uploader</artifactId>
<version>1.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>HAPI FHIR - Examples Uploader</name>
@ -36,17 +35,19 @@
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>

View File

@ -2,7 +2,6 @@ package ca.uhn.fhir.exampleuploader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -10,7 +9,6 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
@ -113,10 +111,10 @@ public class Uploader {
for (Entry next : bundle.getEntry()) {
List<ResourceReferenceInfo> refs = ctx.newTerser().getAllResourceReferences(next.getResource());
for (ResourceReferenceInfo nextRef : refs) {
// if (nextRef.getResourceReference().getReferenceElement().isAbsolute()) {
// ourLog.info("Discarding absolute reference: {}", nextRef.getResourceReference().getReferenceElement().getValue());
// nextRef.getResourceReference().getReferenceElement().setValue(null);
// }
// if (nextRef.getResourceReference().getReferenceElement().isAbsolute()) {
// ourLog.info("Discarding absolute reference: {}", nextRef.getResourceReference().getReferenceElement().getValue());
// nextRef.getResourceReference().getReferenceElement().setValue(null);
// }
nextRef.getResourceReference().getReferenceElement().setValue(nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue());
String value = nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue();
if (!ids.contains(value) && !nextRef.getResourceReference().getReferenceElement().isLocal()) {
@ -127,13 +125,13 @@ public class Uploader {
}
}
}
// for (Entry next : bundle.getEntry()) {
// if (next.getResource().getId().hasIdPart() && Character.isLetter(next.getResource().getId().getIdPart().charAt(0))) {
// next.getTransaction().setUrl(next.getResource().getResourceName() + '/' + next.getResource().getId().getIdPart());
// next.getTransaction().setMethod(HTTPVerbEnum.PUT);
// }
// }
// for (Entry next : bundle.getEntry()) {
// if (next.getResource().getId().hasIdPart() && Character.isLetter(next.getResource().getId().getIdPart().charAt(0))) {
// next.getTransaction().setUrl(next.getResource().getResourceName() + '/' + next.getResource().getId().getIdPart());
// next.getTransaction().setMethod(HTTPVerbEnum.PUT);
// }
// }
ourLog.info("{} good references", goodRefs);

View File

@ -1696,13 +1696,17 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
}
/**
* May be implemented by subclasses to validate resources prior to storage
* May be overridden by subclasses to validate resources prior to storage
*
* @param theResource
* The resource that is about to be stored
*/
protected void preProcessResourceForStorage(T theResource) {
// nothing by default
if (theResource.getId().hasIdPart()) {
if (!theResource.getId().isIdPartValid()) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithInvalidId", theResource.getId().getIdPart()));
}
}
}
@Override
@ -2296,7 +2300,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
try {
entity = readEntityLatestVersion(resourceId);
} catch (ResourceNotFoundException e) {
if (Character.isDigit(theResource.getId().getIdPart().charAt(0))) {
if (resourceId.isIdPartValidLong()) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getId().getIdPart()));
}
return doCreate(theResource, null, thePerformIndexing);

View File

@ -32,6 +32,7 @@ import javax.measure.quantity.Quantity;
import javax.measure.unit.NonSI;
import javax.measure.unit.Unit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import ca.uhn.fhir.context.ConfigurationException;
@ -80,8 +81,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
@ -143,8 +143,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public ArrayList<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
@ -191,18 +190,12 @@ public class SearchParamExtractorDstu2 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()); DurationDt
* newValue = new DurationDt(); 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()); DurationDt newValue = new DurationDt(); newValue.setSystem(UCUM_NS);
* newValue.setCode(UCUM.DAY.getSymbol()); newValue.setValue(dayValue); nextValue=newValue; }
*/
}
}
@ -246,8 +239,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
@ -281,7 +273,8 @@ public class SearchParamExtractorDstu2 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 {
@ -302,8 +295,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
@ -317,11 +309,11 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
String nextPath = nextSpDef.getPath();
String resourceName = nextSpDef.getName();
if (isBlank(nextPath)) {
// TODO: implement phonetic, and any others that have no path
if ("Questionnaire".equals(def.getName()) && nextSpDef.getName().equals("title")) {
Questionnaire q = (Questionnaire) theResource;
String title = q.getGroup().getTitle();
@ -399,8 +391,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
@ -411,7 +402,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
ValueSet vs = (ValueSet) theResource;
useSystem = vs.getCodeSystem().getSystem();
}
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
@ -442,32 +433,41 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
}
for (Object nextObject : extractValues(nextPath, theResource)) {
// Patient:language
// Patient:language
if (nextObject instanceof Patient.Communication) {
Communication nextValue = (Patient.Communication) nextObject;
nextObject= nextValue.getLanguage();
nextObject = nextValue.getLanguage();
}
if (nextObject instanceof IdentifierDt) {
IdentifierDt nextValue = (IdentifierDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
systems.add(nextValue.getSystemElement().getValueAsString());
codes.add(nextValue.getValueElement().getValue());
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 ContactPointDt) {
ContactPointDt nextValue = (ContactPointDt) nextObject;
if (nextValue.isEmpty()) {
ContactPointDt nextValue = (ContactPointDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if (isNotBlank(needContactPointSystem)) {
if (!needContactPointSystem.equals(nextValue.getSystemElement().getValueAsString())) {
continue;
}
if (isNotBlank(needContactPointSystem)) {
if (!needContactPointSystem.equals(nextValue.getSystemElement().getValueAsString())) {
continue;
}
}
systems.add(nextValue.getSystemElement().getValueAsString());
codes.add(nextValue.getValueElement().getValue());
}
systems.add(nextValue.getSystemElement().getValueAsString());
codes.add(nextValue.getValueElement().getValue());
} else if (nextObject instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
if (nextValue.isEmpty()) {
@ -481,38 +481,19 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
codes.add(nextValue.getValueAsString());
} else if (nextObject instanceof CodingDt) {
CodingDt nextValue = (CodingDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
String nextSystem = nextValue.getSystemElement().getValueAsString();
String nextCode = nextValue.getCodeElement().getValue();
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
systems.add(nextSystem);
codes.add(nextCode);
}
if (!nextValue.getDisplayElement().isEmpty()) {
systems.add(null);
codes.add(nextValue.getDisplayElement().getValue());
}
extractTokensFromCoding(systems, codes, theEntity, retVal, nextSpDef, nextValue);
} else if (nextObject instanceof CodeableConceptDt) {
CodeableConceptDt nextCC = (CodeableConceptDt) nextObject;
if (!nextCC.getTextElement().isEmpty()) {
String value = nextCC.getTextElement().getValue();
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);
addStringParam(theEntity, retVal, nextSpDef, nextCC.getTextElement().getValue());
}
extractTokensFromCodeableConcept(systems, codes, nextCC);
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
} else if (nextObject instanceof RestSecurity) {
// Conformance.security search param points to something kind of useless right now - This should probably be fixed.
RestSecurity sec = (RestSecurity)nextObject;
RestSecurity sec = (RestSecurity) nextObject;
for (BoundCodeableConceptDt<RestfulSecurityServiceEnum> nextCC : sec.getService()) {
extractTokensFromCodeableConcept(systems, codes, nextCC);
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
}
} else {
if (!multiType) {
@ -560,22 +541,35 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
return retVal;
}
private void extractTokensFromCodeableConcept(List<String> systems, List<String> codes, CodeableConceptDt nextCC) {
for (CodingDt nextCoding : nextCC.getCoding()) {
if (nextCoding.isEmpty()) {
continue;
}
private void addStringParam(ResourceTable theEntity, ArrayList<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);
}
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConceptDt theCodeableConcept, ResourceTable theEntity,
ArrayList<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
for (CodingDt nextCoding : theCodeableConcept.getCoding()) {
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
}
}
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, ArrayList<BaseResourceIndexedSearchParam> theListToPopulate,
RuntimeSearchParam theParameterDef, CodingDt nextCoding) {
if (nextCoding != null && !nextCoding.isEmpty()) {
String nextSystem = nextCoding.getSystemElement().getValueAsString();
String nextCode = nextCoding.getCodeElement().getValue();
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
systems.add(nextSystem);
codes.add(nextCode);
theSystems.add(nextSystem);
theCodes.add(nextCode);
}
if (!nextCoding.getDisplayElement().isEmpty()) {
systems.add(null);
codes.add(nextCoding.getDisplayElement().getValue());
addStringParam(theEntity, theListToPopulate, theParameterDef, nextCoding.getDisplayElement().getValue());
}
}

View File

@ -72,7 +72,7 @@ public class FhirResourceDaoDstu1Test extends BaseJpaTest {
ourPatientDao.create(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("clients may only assign IDs which begin with a non-numeric"));
assertThat(e.getMessage(), containsString("clients may only assign IDs which contain at least one non-numeric"));
}
}
@ -117,7 +117,7 @@ public class FhirResourceDaoDstu1Test extends BaseJpaTest {
ourPatientDao.update(p1);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("clients may only assign IDs which begin with a non-numeric"));
assertThat(e.getMessage(), containsString("clients may only assign IDs which contain at least one non-numeric"));
}
}

View File

@ -103,17 +103,22 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
private static IFhirResourceDao<DiagnosticReport> ourDiagnosticReportDao;
private static IFhirResourceDao<Encounter> ourEncounterDao;
private static FhirContext ourFhirCtx;
private static IServerInterceptor ourInterceptor;
private static IFhirResourceDao<Location> ourLocationDao;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2Test.class);
private static IFhirResourceDao<Observation> ourObservationDao;
private static IFhirResourceDao<Organization> ourOrganizationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirResourceDao<Practitioner> ourPractitionerDao;
private static IFhirResourceDao<Questionnaire> ourQuestionnaireDao;
@SuppressWarnings("unused")
private static IFhirResourceDao<QuestionnaireResponse> ourQuestionnaireResponseDao;
private static IFhirResourceDao<Questionnaire> ourQuestionnaireDao;
private static IFhirSystemDao<Bundle> ourSystemDao;
private static IFhirResourceDao<Practitioner> ourPractitionerDao;
private static IServerInterceptor ourInterceptor;
@Before
public void before() {
reset(ourInterceptor);
}
private List<String> extractNames(IBundleProvider theSearch) {
ArrayList<String> retVal = new ArrayList<String>();
@ -124,62 +129,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
return retVal;
}
@Test
public void testCreateOperationOutcome() {
/*
* If any of this ever fails, it means that one of the OperationOutcome issue severity codes has changed code
* value across versions. We store the string as a constant, so something will need to be fixed.
*/
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.ERROR.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.ERROR.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR);
assertEquals(ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum.ERROR.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR);
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.INFORMATION.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.INFORMATION.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO);
assertEquals(ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum.INFORMATION.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO);
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.WARNING.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.WARNING.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN);
assertEquals(ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum.WARNING.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN);
}
@Test
public void testRead() {
Observation o1 = new Observation();
o1.getCode().addCoding().setSystem("foo").setCode("testRead");
IIdType id1 = ourObservationDao.create(o1).getId();
/*
* READ
*/
reset(ourInterceptor);
Observation obs = ourObservationDao.read(id1.toUnqualifiedVersionless());
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
// Verify interceptor
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
verify(ourInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
ActionRequestDetails details = detailsCapt.getValue();
assertEquals(id1.toUnqualifiedVersionless().getValue(), details.getId().toUnqualifiedVersionless().getValue());
assertEquals("Observation", details.getResourceType());
/*
* VREAD
*/
assertTrue(id1.hasVersionIdPart()); // just to make sure..
reset(ourInterceptor);
obs = ourObservationDao.read(id1);
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
// Verify interceptor
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
verify(ourInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
details = detailsCapt.getValue();
assertEquals(id1.toUnqualified().getValue(), details.getId().toUnqualified().getValue());
assertEquals("Observation", details.getResourceType());
}
@Test
public void testChoiceParamConcept() {
Observation o1 = new Observation();
@ -193,7 +142,8 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
assertEquals(id1, found.getResources(0, 1).get(0).getIdElement());
}
}
@Test
public void testChoiceParamDate() {
Observation o2 = new Observation();
@ -269,17 +219,20 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
@Test
public void testCreateNumericIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123");
try {
ourPatientDao.create(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Can not create resource with ID[123], ID must not be supplied"));
}
public void testCreateOperationOutcome() {
/*
* If any of this ever fails, it means that one of the OperationOutcome issue severity codes has changed code
* value across versions. We store the string as a constant, so something will need to be fixed.
*/
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.ERROR.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.ERROR.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR);
assertEquals(ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum.ERROR.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR);
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.INFORMATION.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.INFORMATION.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO);
assertEquals(ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum.INFORMATION.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_INFO);
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.WARNING.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN);
assertEquals(ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum.WARNING.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN);
assertEquals(ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum.WARNING.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_WARN);
}
@Test
@ -298,20 +251,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
assertEquals("my message", oo.getIssue().get(0).getDiagnostics());
}
@Test
public void testCreateTextIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/ABC");
try {
ourPatientDao.create(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Can not create resource with ID[ABC], ID must not be supplied"));
}
}
@Test
public void testCreateSummaryFails() {
@ -331,6 +270,34 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
}
@Test
public void testCreateTextIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/ABC");
try {
ourPatientDao.create(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Can not create resource with ID[ABC], ID must not be supplied"));
}
}
@Test
public void testCreateWithIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/abc");
try {
ourPatientDao.create(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Can not create resource with ID[abc], ID must not be supplied"));
}
}
@Test
public void testCreateWithIfNoneExistBasic() {
String methodName = "testCreateWithIfNoneExistBasic";
@ -383,6 +350,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
@Test
public void testCreateWithInvalidReferenceFailsGracefully() {
Patient patient = new Patient();
@ -1028,6 +996,44 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
@Test
public void testRead() {
Observation o1 = new Observation();
o1.getCode().addCoding().setSystem("foo").setCode("testRead");
IIdType id1 = ourObservationDao.create(o1).getId();
/*
* READ
*/
reset(ourInterceptor);
Observation obs = ourObservationDao.read(id1.toUnqualifiedVersionless());
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
// Verify interceptor
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
verify(ourInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
ActionRequestDetails details = detailsCapt.getValue();
assertEquals(id1.toUnqualifiedVersionless().getValue(), details.getId().toUnqualifiedVersionless().getValue());
assertEquals("Observation", details.getResourceType());
/*
* VREAD
*/
assertTrue(id1.hasVersionIdPart()); // just to make sure..
reset(ourInterceptor);
obs = ourObservationDao.read(id1);
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
// Verify interceptor
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
verify(ourInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
details = detailsCapt.getValue();
assertEquals(id1.toUnqualified().getValue(), details.getId().toUnqualified().getValue());
assertEquals("Observation", details.getResourceType());
}
@Test
public void testReadForcedIdVersionHistory() throws InterruptedException {
Patient p1 = new Patient();
@ -1544,55 +1550,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
}
@Test
public void testSearchPractitionerPhoneAndEmailParam() {
String methodName = "testSearchPractitionerPhoneAndEmailParam";
IIdType id1;
{
Practitioner patient = new Practitioner();
patient.getName().addFamily(methodName);
patient.addTelecom().setSystem(ContactPointSystemEnum.PHONE).setValue("123");
id1 = ourPractitionerDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id2;
{
Practitioner patient = new Practitioner();
patient.getName().addFamily(methodName);
patient.addTelecom().setSystem(ContactPointSystemEnum.EMAIL).setValue("abc");
id2 = ourPractitionerDao.create(patient).getId().toUnqualifiedVersionless();
}
Map<String, IQueryParameterType> params;
List<IIdType> patients;
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringDt(methodName));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(2, patients.size());
assertThat(patients, containsInAnyOrder(id1, id2));
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringParam(methodName));
params.put(Practitioner.SP_EMAIL, new TokenParam(null, "abc"));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(1, patients.size());
assertThat(patients, containsInAnyOrder(id2));
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringParam(methodName));
params.put(Practitioner.SP_EMAIL, new TokenParam(null, "123"));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(0, patients.size());
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringParam(methodName));
params.put(Practitioner.SP_PHONE, new TokenParam(null, "123"));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(1, patients.size());
assertThat(patients, containsInAnyOrder(id1));
}
@Test
public void testSearchNameParam() {
IIdType id1;
@ -1669,6 +1626,55 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
}
@Test
public void testSearchPractitionerPhoneAndEmailParam() {
String methodName = "testSearchPractitionerPhoneAndEmailParam";
IIdType id1;
{
Practitioner patient = new Practitioner();
patient.getName().addFamily(methodName);
patient.addTelecom().setSystem(ContactPointSystemEnum.PHONE).setValue("123");
id1 = ourPractitionerDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id2;
{
Practitioner patient = new Practitioner();
patient.getName().addFamily(methodName);
patient.addTelecom().setSystem(ContactPointSystemEnum.EMAIL).setValue("abc");
id2 = ourPractitionerDao.create(patient).getId().toUnqualifiedVersionless();
}
Map<String, IQueryParameterType> params;
List<IIdType> patients;
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringDt(methodName));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(2, patients.size());
assertThat(patients, containsInAnyOrder(id1, id2));
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringParam(methodName));
params.put(Practitioner.SP_EMAIL, new TokenParam(null, "abc"));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(1, patients.size());
assertThat(patients, containsInAnyOrder(id2));
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringParam(methodName));
params.put(Practitioner.SP_EMAIL, new TokenParam(null, "123"));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(0, patients.size());
params = new HashMap<String, IQueryParameterType>();
params.put(Practitioner.SP_FAMILY, new StringParam(methodName));
params.put(Practitioner.SP_PHONE, new TokenParam(null, "123"));
patients = toUnqualifiedVersionlessIds(ourPractitionerDao.search(params));
assertEquals(1, patients.size());
assertThat(patients, containsInAnyOrder(id1));
}
@Test
public void testSearchResourceLinkWithChain() {
Patient patient = new Patient();
@ -1977,10 +1983,23 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
assertEquals(0, ourPatientDao.search(map).size());
}
{
// Complete match
SearchParameterMap map = new SearchParameterMap();
map.add(Patient.SP_LANGUAGE, new TokenParam(null, "testSearchTokenParamComText", true));
assertEquals(1, ourPatientDao.search(map).size());
}
{
// Left match
SearchParameterMap map = new SearchParameterMap();
map.add(Patient.SP_LANGUAGE, new TokenParam(null, "testSearchTokenParamcomtex", true));
assertEquals(1, ourPatientDao.search(map).size());
}
{
// Right match
SearchParameterMap map = new SearchParameterMap();
map.add(Patient.SP_LANGUAGE, new TokenParam(null, "testSearchTokenParamComTex", true));
assertEquals(1, ourPatientDao.search(map).size());
}
{
SearchParameterMap map = new SearchParameterMap();
TokenOrListParam listParam = new TokenOrListParam();
@ -2036,117 +2055,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
@Test
public void testSearchWithTagParameter() {
String methodName = "testSearchWithTagParameter";
IIdType tag1id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
TagList tagList = new TagList();
tagList.addTag("urn:taglist", methodName + "1a");
tagList.addTag("urn:taglist", methodName + "1b");
ResourceMetadataKeyEnum.TAG_LIST.put(org, tagList);
tag1id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
IIdType tag2id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
TagList tagList = new TagList();
tagList.addTag("urn:taglist", methodName + "2a");
tagList.addTag("urn:taglist", methodName + "2b");
ResourceMetadataKeyEnum.TAG_LIST.put(org, tagList);
tag2id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
{
// One tag
SearchParameterMap params = new SearchParameterMap();
params.add("_tag", new TokenParam("urn:taglist", methodName + "1a"));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
{
// Code only
SearchParameterMap params = new SearchParameterMap();
params.add("_tag", new TokenParam(null, methodName + "1a"));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
{
// Or tags
SearchParameterMap params = new SearchParameterMap();
TokenOrListParam orListParam = new TokenOrListParam();
orListParam.add(new TokenParam("urn:taglist", methodName + "1a"));
orListParam.add(new TokenParam("urn:taglist", methodName + "2a"));
params.add("_tag", orListParam);
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id, tag2id));
}
// TODO: get multiple/AND working
{
// And tags
SearchParameterMap params = new SearchParameterMap();
TokenAndListParam andListParam = new TokenAndListParam();
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "1a"));
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "2a"));
params.add("_tag", andListParam);
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertEquals(0, patients.size());
}
{
// And tags
SearchParameterMap params = new SearchParameterMap();
TokenAndListParam andListParam = new TokenAndListParam();
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "1a"));
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "1b"));
params.add("_tag", andListParam);
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
}
@Test
public void testSearchWithSecurityAndProfileParams() {
String methodName = "testSearchWithSecurityAndProfileParams";
IIdType tag1id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
List<BaseCodingDt> security = new ArrayList<BaseCodingDt>();
security.add(new CodingDt("urn:taglist", methodName + "1a"));
ResourceMetadataKeyEnum.SECURITY_LABELS.put(org, security);
tag1id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
IIdType tag2id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
List<IdDt> security = new ArrayList<IdDt>();
security.add(new IdDt("http://" + methodName));
ResourceMetadataKeyEnum.PROFILES.put(org, security);
tag2id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
{
SearchParameterMap params = new SearchParameterMap();
params.add("_security", new TokenParam("urn:taglist", methodName + "1a"));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
{
SearchParameterMap params = new SearchParameterMap();
params.add("_profile", new UriParam("http://" + methodName));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag2id));
}
}
@Test
public void testSearchWithIncludes() {
IIdType parentOrgId;
@ -2236,10 +2144,10 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
public void testSearchWithIncludesThatHaveTextId() {
{
Organization org = new Organization();
org.setId("testSearchWithIncludesThatHaveTextId_id1");
org.setId("testSearchWithIncludesThatHaveTextIdid1");
org.getNameElement().setValue("testSearchWithIncludesThatHaveTextId_O1");
IIdType orgId = ourOrganizationDao.update(org).getId();
assertThat(orgId.getValue(), endsWith("Organization/testSearchWithIncludesThatHaveTextId_id1/_history/1"));
assertThat(orgId.getValue(), endsWith("Organization/testSearchWithIncludesThatHaveTextIdid1/_history/1"));
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
@ -2309,6 +2217,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
}
@Test
public void testSearchWithMissingQuantity() {
IIdType notMissing;
@ -2449,6 +2358,116 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
@Test
public void testSearchWithSecurityAndProfileParams() {
String methodName = "testSearchWithSecurityAndProfileParams";
IIdType tag1id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
List<BaseCodingDt> security = new ArrayList<BaseCodingDt>();
security.add(new CodingDt("urn:taglist", methodName + "1a"));
ResourceMetadataKeyEnum.SECURITY_LABELS.put(org, security);
tag1id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
IIdType tag2id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
List<IdDt> security = new ArrayList<IdDt>();
security.add(new IdDt("http://" + methodName));
ResourceMetadataKeyEnum.PROFILES.put(org, security);
tag2id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
{
SearchParameterMap params = new SearchParameterMap();
params.add("_security", new TokenParam("urn:taglist", methodName + "1a"));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
{
SearchParameterMap params = new SearchParameterMap();
params.add("_profile", new UriParam("http://" + methodName));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag2id));
}
}
@Test
public void testSearchWithTagParameter() {
String methodName = "testSearchWithTagParameter";
IIdType tag1id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
TagList tagList = new TagList();
tagList.addTag("urn:taglist", methodName + "1a");
tagList.addTag("urn:taglist", methodName + "1b");
ResourceMetadataKeyEnum.TAG_LIST.put(org, tagList);
tag1id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
IIdType tag2id;
{
Organization org = new Organization();
org.getNameElement().setValue("FOO");
TagList tagList = new TagList();
tagList.addTag("urn:taglist", methodName + "2a");
tagList.addTag("urn:taglist", methodName + "2b");
ResourceMetadataKeyEnum.TAG_LIST.put(org, tagList);
tag2id = ourOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
{
// One tag
SearchParameterMap params = new SearchParameterMap();
params.add("_tag", new TokenParam("urn:taglist", methodName + "1a"));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
{
// Code only
SearchParameterMap params = new SearchParameterMap();
params.add("_tag", new TokenParam(null, methodName + "1a"));
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
{
// Or tags
SearchParameterMap params = new SearchParameterMap();
TokenOrListParam orListParam = new TokenOrListParam();
orListParam.add(new TokenParam("urn:taglist", methodName + "1a"));
orListParam.add(new TokenParam("urn:taglist", methodName + "2a"));
params.add("_tag", orListParam);
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id, tag2id));
}
// TODO: get multiple/AND working
{
// And tags
SearchParameterMap params = new SearchParameterMap();
TokenAndListParam andListParam = new TokenAndListParam();
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "1a"));
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "2a"));
params.add("_tag", andListParam);
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertEquals(0, patients.size());
}
{
// And tags
SearchParameterMap params = new SearchParameterMap();
TokenAndListParam andListParam = new TokenAndListParam();
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "1a"));
andListParam.addValue(new TokenOrListParam("urn:taglist", methodName + "1b"));
params.add("_tag", andListParam);
List<IIdType> patients = toUnqualifiedVersionlessIds(ourOrganizationDao.search(params));
assertThat(patients, containsInAnyOrder(tag1id));
}
}
@Test
public void testSearchWithToken() {
IIdType notMissing;
@ -3066,18 +3085,13 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
@Test
public void testUpdateFailsForUnknownIdWithNumberThenText() {
public void testUpdateDoesntFailForUnknownIdWithNumberThenText() {
String methodName = "testUpdateFailsForUnknownIdWithNumberThenText";
Patient p = new Patient();
p.setId("0" + methodName);
p.addName().addFamily(methodName);
try {
ourPatientDao.update(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("no resource with this ID exists and clients may only assign IDs which begin with a non-numeric character on this server"));
}
ourPatientDao.update(p);
}
@Test
@ -3157,6 +3171,50 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
}
@Test
public void testUpdateWithNumericIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123");
try {
ourPatientDao.update(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("clients may only assign IDs which contain at least one non-numeric"));
}
}
@Test
public void testUpdateWithInvalidIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123:456");
try {
ourPatientDao.update(p);
fail();
} catch (InvalidRequestException e) {
assertEquals("Can not process entity with ID[123:456], this is not a valid FHIR ID", e.getMessage());
}
}
@Test
public void testUpdateWithNumericThenTextIdSucceeds() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123abc");
IIdType id = ourPatientDao.update(p).getId();
assertEquals("123abc", id.getIdPart());
assertEquals("1", id.getVersionIdPart());
p = ourPatientDao.read(id.toUnqualifiedVersionless());
assertEquals("Patient/123abc", p.getId().toUnqualifiedVersionless().getValue());
assertEquals("Hello", p.getName().get(0).getFamily().get(0).getValue());
}
@SuppressWarnings({ "rawtypes" })
private List toList(IBundleProvider theSearch) {
return theSearch.getResources(0, theSearch.size());
@ -3197,11 +3255,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
daoConfig.setInterceptors(ourInterceptor);
}
@Before
public void before() {
reset(ourInterceptor);
}
private static void deleteEverything() {
FhirSystemDaoDstu2Test.doDeleteEverything(ourSystemDao);

View File

@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
@ -130,6 +131,13 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
// private static JpaConformanceProvider ourConfProvider;
private void checkParamMissing(String paramName) throws IOException, ClientProtocolException {
HttpGet get = new HttpGet(ourServerBase + "/Observation?" + paramName + ":missing=false");
CloseableHttpResponse resp = ourHttpClient.execute(get);
IOUtils.closeQuietly(resp.getEntity().getContent());
assertEquals(200, resp.getStatusLine().getStatusCode());
}
private void delete(String theResourceType, String theParamName, String theParamValue) {
Bundle resources;
do {
@ -145,148 +153,6 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
} while (resources.size() > 0);
}
/**
* See #198
*/
@Test
public void testSortFromResourceProvider() {
Patient p;
String methodName = "testSortFromResourceProvider";
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Daniel").addFamily("Adams");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Aaron").addFamily("Alexis");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Carol").addFamily("Allen");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Ruth").addFamily("Black");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Brian").addFamily("Brooks");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Susan").addFamily("Clark");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Amy").addFamily("Clark");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Anthony").addFamily("Coleman");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Steven").addFamily("Coleman");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Lisa").addFamily("Coleman");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Ruth").addFamily("Cook");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Betty").addFamily("Davis");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Joshua").addFamily("Diaz");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Brian").addFamily("Gracia");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Stephan").addFamily("Graham");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Sarah").addFamily("Graham");
ourClient.create().resource(p).execute();
//@formatter:off
Bundle resp = ourClient
.search()
.forResource(Patient.class)
.where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", methodName))
.sort().ascending(Patient.FAMILY)
.sort().ascending(Patient.GIVEN)
.limitTo(100)
.execute();
//@formatter:on
List<String> names = toNameList(resp);
ourLog.info(StringUtils.join(names, '\n'));
//@formatter:off
assertThat(names, contains( // this matches in order only
"Daniel Adams",
"Aaron Alexis",
"Carol Allen",
"Ruth Black",
"Brian Brooks",
"Amy Clark",
"Susan Clark",
"Anthony Coleman",
"Lisa Coleman",
"Steven Coleman",
"Ruth Cook",
"Betty Davis",
"Joshua Diaz",
"Brian Gracia",
"Sarah Graham",
"Stephan Graham"));
//@formatter:om
}
private List<String> toNameList(Bundle resp) {
List<String> names = new ArrayList<String>();
for (BundleEntry next : resp.getEntries()) {
Patient nextPt= (Patient) next.getResource();
String nextStr = nextPt.getNameFirstRep().getGivenAsSingleString()+ " " + nextPt.getNameFirstRep().getFamilyAsSingleString();
if (isNotBlank(nextStr)) {
names.add(nextStr);
}
}
return names;
}
private void deleteToken(String theResourceType, String theParamName, String theParamSystem, String theParamValue) {
Bundle resources = ourClient.search().forResource(theResourceType).where(new TokenClientParam(theParamName).exactly().systemAndCode(theParamSystem, theParamValue)).execute();
for (IResource next : resources.toListOfResources()) {
@ -347,46 +213,34 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
@Test
public void testMetaOperations() throws Exception {
String methodName = "testMetaOperations";
public void testCreateQuestionnaireResponseWithValidation() throws IOException {
ValueSet options = new ValueSet();
options.getCodeSystem().setSystem("urn:system").addConcept().setCode("code0");
IIdType optId = ourClient.create().resource(options).execute().getId();
Patient pt = new Patient();
pt.addName().addFamily(methodName);
IIdType id = ourClient.create().resource(pt).execute().getId().toUnqualifiedVersionless();
Questionnaire q = new Questionnaire();
q.getGroup().addQuestion().setLinkId("link0").setRequired(false).setType(AnswerFormatEnum.CHOICE).setOptions(new ResourceReferenceDt(optId));
IIdType qId = ourClient.create().resource(q).execute().getId();
MetaDt meta = ourClient.meta().get(MetaDt.class).fromResource(id).execute();
assertEquals(0, meta.getTag().size());
QuestionnaireResponse qa;
MetaDt inMeta = new MetaDt();
inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
meta = ourClient.meta().add().onResource(id).meta(inMeta).execute();
assertEquals(1, meta.getTag().size());
// Good code
inMeta = new MetaDt();
inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
meta = ourClient.meta().delete().onResource(id).meta(inMeta).execute();
assertEquals(0, meta.getTag().size());
qa = new QuestionnaireResponse();
qa.getQuestionnaire().setReference(qId.toUnqualifiedVersionless().getValue());
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new CodingDt().setSystem("urn:system").setCode("code0"));
ourClient.create().resource(qa).execute();
}
// Bad code
@Test
public void testGetResourceCountsOperation() throws Exception {
String methodName = "testMetaOperations";
Patient pt = new Patient();
pt.addName().addFamily(methodName);
ourClient.create().resource(pt).execute().getId().toUnqualifiedVersionless();
HttpGet get = new HttpGet(ourServerBase + "/$get-resource-counts");
CloseableHttpResponse response = ourHttpClient.execute(get);
qa = new QuestionnaireResponse();
qa.getQuestionnaire().setReference(qId.toUnqualifiedVersionless().getValue());
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new CodingDt().setSystem("urn:system").setCode("code1"));
try {
assertEquals(200, response.getStatusLine().getStatusCode());
String output = IOUtils.toString(response.getEntity().getContent());
IOUtils.closeQuietly(response.getEntity().getContent());
ourLog.info(output);
assertThat(output, containsString("<parameter><name value=\"Patient\"/><valueInteger value=\""));
} finally {
response.close();
ourClient.create().resource(qa).execute();
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Question with linkId[link0]"));
}
}
@ -427,34 +281,22 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
@Test
public void testCreateQuestionnaireResponseWithValidation() throws IOException {
ValueSet options = new ValueSet();
options.getCodeSystem().setSystem("urn:system").addConcept().setCode("code0");
IIdType optId = ourClient.create().resource(options).execute().getId();
Questionnaire q = new Questionnaire();
q.getGroup().addQuestion().setLinkId("link0").setRequired(false).setType(AnswerFormatEnum.CHOICE).setOptions(new ResourceReferenceDt(optId));
IIdType qId = ourClient.create().resource(q).execute().getId();
public void testCreateResourceReturnsOperationOutcomeByDefault() throws IOException {
String resource = "<Patient xmlns=\"http://hl7.org/fhir\"></Patient>";
QuestionnaireResponse qa;
HttpPost post = new HttpPost(ourServerBase + "/Patient");
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
// Good code
qa = new QuestionnaireResponse();
qa.getQuestionnaire().setReference(qId.toUnqualifiedVersionless().getValue());
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new CodingDt().setSystem("urn:system").setCode("code0"));
ourClient.create().resource(qa).execute();
// Bad code
qa = new QuestionnaireResponse();
qa.getQuestionnaire().setReference(qId.toUnqualifiedVersionless().getValue());
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new CodingDt().setSystem("urn:system").setCode("code1"));
CloseableHttpResponse response = ourHttpClient.execute(post);
try {
ourClient.create().resource(qa).execute();
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Question with linkId[link0]"));
assertEquals(201, response.getStatusLine().getStatusCode());
String respString = IOUtils.toString(response.getEntity().getContent());
ourLog.info(response.toString());
ourLog.info(respString);
assertThat(respString, containsString("<OperationOutcome xmlns=\"http://hl7.org/fhir\">"));
} finally {
response.getEntity().getContent().close();
response.close();
}
}
@ -478,27 +320,6 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
}
@Test
public void testCreateResourceReturnsOperationOutcomeByDefault() throws IOException {
String resource = "<Patient xmlns=\"http://hl7.org/fhir\"></Patient>";
HttpPost post = new HttpPost(ourServerBase + "/Patient");
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
CloseableHttpResponse response = ourHttpClient.execute(post);
try {
assertEquals(201, response.getStatusLine().getStatusCode());
String respString = IOUtils.toString(response.getEntity().getContent());
ourLog.info(response.toString());
ourLog.info(respString);
assertThat(respString, containsString("<OperationOutcome xmlns=\"http://hl7.org/fhir\">"));
} finally {
response.getEntity().getContent().close();
response.close();
}
}
@Test
public void testDeepChaining() {
delete("Location", Location.SP_NAME, "testDeepChainingL1");
@ -604,8 +425,7 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
/*
* Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to
* make sure that works too..
* Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to make sure that works too..
*/
Socket sock = new Socket();
sock.setSoTimeout(3000);
@ -845,6 +665,27 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
ourLog.info(ids.toString());
}
@Test
public void testGetResourceCountsOperation() throws Exception {
String methodName = "testMetaOperations";
Patient pt = new Patient();
pt.addName().addFamily(methodName);
ourClient.create().resource(pt).execute().getId().toUnqualifiedVersionless();
HttpGet get = new HttpGet(ourServerBase + "/$get-resource-counts");
CloseableHttpResponse response = ourHttpClient.execute(get);
try {
assertEquals(200, response.getStatusLine().getStatusCode());
String output = IOUtils.toString(response.getEntity().getContent());
IOUtils.closeQuietly(response.getEntity().getContent());
ourLog.info(output);
assertThat(output, containsString("<parameter><name value=\"Patient\"/><valueInteger value=\""));
} finally {
response.close();
}
}
/**
* See issue #52
*/
@ -863,6 +704,29 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
@Test
public void testMetaOperations() throws Exception {
String methodName = "testMetaOperations";
Patient pt = new Patient();
pt.addName().addFamily(methodName);
IIdType id = ourClient.create().resource(pt).execute().getId().toUnqualifiedVersionless();
MetaDt meta = ourClient.meta().get(MetaDt.class).fromResource(id).execute();
assertEquals(0, meta.getTag().size());
MetaDt inMeta = new MetaDt();
inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
meta = ourClient.meta().add().onResource(id).meta(inMeta).execute();
assertEquals(1, meta.getTag().size());
inMeta = new MetaDt();
inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
meta = ourClient.meta().delete().onResource(id).meta(inMeta).execute();
assertEquals(0, meta.getTag().size());
}
/**
* Test for issue #60
*/
@ -979,7 +843,8 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01");
IdDt p1Id = (IdDt) ourClient.create().resource(p1).execute().getId();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint().execute();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint()
.execute();
assertEquals(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());
@ -1172,6 +1037,33 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
assertEquals(BundleEntrySearchModeEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
}
@Test
public void testSearchWithTextInexactMatch() throws Exception {
Observation obs = new Observation();
obs.getCode().setText("THIS_IS_THE_TEXT");
obs.getCode().addCoding().setSystem("SYSTEM").setCode("CODE").setDisplay("THIS_IS_THE_DISPLAY");
ourClient.create().resource(obs).execute();
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_TEXT");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_");
testSearchReturnsResults("/Observation?code%3Atext=this_is_the_");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_DISPLAY");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_disp");
}
private void testSearchReturnsResults(String search) throws IOException, ClientProtocolException {
int matches;
HttpGet get = new HttpGet(ourServerBase + search);
CloseableHttpResponse response = ourHttpClient.execute(get);
String resp = IOUtils.toString(response.getEntity().getContent());
IOUtils.closeQuietly(response.getEntity().getContent());
ourLog.info(resp);
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, resp);
matches = bundle.getTotal();
assertThat(matches, greaterThan(0));
}
@Test
public void testSearchWithMissing() throws Exception {
ourLog.info("Starting testSearchWithMissing");
@ -1242,6 +1134,144 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
assertThat("Wanted " + orgMissing + " but found: " + list, list, containsInRelativeOrder(orgMissing));
}
@Test
public void testSearchWithMissing2() throws Exception {
checkParamMissing(Observation.SP_CODE);
checkParamMissing(Observation.SP_CATEGORY);
checkParamMissing(Observation.SP_VALUE_STRING);
checkParamMissing(Observation.SP_ENCOUNTER);
checkParamMissing(Observation.SP_DATE);
}
/**
* See #198
*/
@Test
public void testSortFromResourceProvider() {
Patient p;
String methodName = "testSortFromResourceProvider";
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Daniel").addFamily("Adams");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Aaron").addFamily("Alexis");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Carol").addFamily("Allen");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Ruth").addFamily("Black");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Brian").addFamily("Brooks");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Susan").addFamily("Clark");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Amy").addFamily("Clark");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Anthony").addFamily("Coleman");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Steven").addFamily("Coleman");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Lisa").addFamily("Coleman");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Ruth").addFamily("Cook");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Betty").addFamily("Davis");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Joshua").addFamily("Diaz");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Brian").addFamily("Gracia");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Stephan").addFamily("Graham");
ourClient.create().resource(p).execute();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addGiven("Sarah").addFamily("Graham");
ourClient.create().resource(p).execute();
//@formatter:off
Bundle resp = ourClient
.search()
.forResource(Patient.class)
.where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", methodName))
.sort().ascending(Patient.FAMILY)
.sort().ascending(Patient.GIVEN)
.limitTo(100)
.execute();
//@formatter:on
List<String> names = toNameList(resp);
ourLog.info(StringUtils.join(names, '\n'));
//@formatter:off
assertThat(names, contains( // this matches in order only
"Daniel Adams",
"Aaron Alexis",
"Carol Allen",
"Ruth Black",
"Brian Brooks",
"Amy Clark",
"Susan Clark",
"Anthony Coleman",
"Lisa Coleman",
"Steven Coleman",
"Ruth Cook",
"Betty Davis",
"Joshua Diaz",
"Brian Gracia",
"Sarah Graham",
"Stephan Graham"));
//@formatter:om
}
/**
* Test for issue #60
*/
@ -1578,6 +1608,18 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
return list;
}
private List<String> toNameList(Bundle resp) {
List<String> names = new ArrayList<String>();
for (BundleEntry next : resp.getEntries()) {
Patient nextPt = (Patient) next.getResource();
String nextStr = nextPt.getNameFirstRep().getGivenAsSingleString() + " " + nextPt.getNameFirstRep().getFamilyAsSingleString();
if (isNotBlank(nextStr)) {
names.add(nextStr);
}
}
return names;
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();

View File

@ -4,6 +4,7 @@ import static org.junit.Assert.*;
import java.math.BigDecimal;
import org.apache.commons.lang3.StringUtils;
import org.junit.BeforeClass;
import org.junit.Test;
@ -17,6 +18,19 @@ public class IdDtTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IdDtTest.class);
@Test
public void testDetectIsIdPartValid() {
assertTrue(new IdDt("0").isIdPartValid());
assertTrue(new IdDt("0a").isIdPartValid());
assertTrue(new IdDt("0abgZZ").isIdPartValid());
assertTrue(new IdDt("---").isIdPartValid());
assertTrue(new IdDt("1.2.3.4").isIdPartValid());
assertFalse(new IdDt(" 1").isIdPartValid());
assertFalse(new IdDt("1:1").isIdPartValid());
assertFalse(new IdDt(StringUtils.leftPad("", 65, '0')).isIdPartValid());
}
@Test
public void testDetectLocal() {
IdDt id;

View File

@ -654,7 +654,33 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
}
return theIdPart.toString();
}
@Override
public boolean isIdPartValid() {
String id = getIdPart();
if (StringUtils.isBlank(id)) {
return false;
}
if (id.length() > 64) {
return false;
}
for (int i = 0; i < id.length(); i++) {
char nextChar = id.charAt(i);
if (nextChar >= 'a' && nextChar <= 'z') {
continue;
}
if (nextChar >= 'A' && nextChar <= 'Z') {
continue;
}
if (nextChar >= '0' && nextChar <= '9') {
continue;
}
if (nextChar == '-' || nextChar == '.') {
continue;
}
return false;
}
return true;
}
/**
* Construct a new ID with with form "urn:uuid:[UUID]" where [UUID] is a new, randomly
* created UUID generated by {@link UUID#randomUUID()}

View File

@ -113,6 +113,15 @@
factory to be used (e.g. for custom authentication, etc.) Thanks
to Chin Huang (@pukkaone) for the pull request!
</action>
<action type="fix" issue="212">
JPA server should reject IDs containing invalid characters (e.g. "abc:123")
but should allow client assigned IDs that contain text but do not start with
text. Thanks to Josh Mandel for reporting!
</action>
<action type="fix">
:text modifier on server and JPA server did not work correctly. Thanks to
Josh Mandel for reporting!
</action>
</release>
<release version="1.1" date="2015-07-13">
<action type="add">