Handle sort by number, uti and token

This commit is contained in:
James Agnew 2015-09-25 16:53:22 -04:00
parent 1361e69177
commit 51a046ea26
9 changed files with 632 additions and 211 deletions

View File

@ -240,22 +240,55 @@ public class RestfulServerUtils {
EncodingEnum retVal = null; EncodingEnum retVal = null;
while (acceptValues.hasMoreElements()) { while (acceptValues.hasMoreElements()) {
String nextAcceptHeaderValue = acceptValues.nextElement(); String nextAcceptHeaderValue = acceptValues.nextElement();
Matcher m = ACCEPT_HEADER_PATTERN.matcher(nextAcceptHeaderValue); StringTokenizer tok = new StringTokenizer(nextAcceptHeaderValue, ",");
float q = 1.0f; while (tok.hasMoreTokens()) {
while (m.find()) { String nextToken = tok.nextToken();
String contentTypeGroup = m.group(1); int startSpaceIndex = -1;
EncodingEnum encoding = Constants.FORMAT_VAL_TO_ENCODING.get(contentTypeGroup); for (int i = 0; i < nextToken.length(); i++) {
if (encoding != null) { if (nextToken.charAt(i) != ' ') {
startSpaceIndex = i;
String name = m.group(3); break;
String value = m.group(4); }
if (name != null && value != null) { }
if ("q".equals(name)) {
try { if (startSpaceIndex == -1) {
q = Float.parseFloat(value); continue;
q = Math.max(q, 0.0f); }
} catch (NumberFormatException e) {
ourLog.debug("Invalid Accept header q value: {}", value); int endSpaceIndex = -1;
for (int i = startSpaceIndex; i < nextToken.length(); i++) {
if (nextToken.charAt(i) == ' ' || nextToken.charAt(i) == ';') {
endSpaceIndex = i;
break;
}
}
float q = 1.0f;
EncodingEnum encoding;
boolean pretty = false;
if (endSpaceIndex == -1) {
if (startSpaceIndex == 0) {
encoding = Constants.FORMAT_VAL_TO_ENCODING.get(nextToken);
} else {
encoding = Constants.FORMAT_VAL_TO_ENCODING.get(nextToken.substring(startSpaceIndex));
}
} else {
encoding = Constants.FORMAT_VAL_TO_ENCODING.get(nextToken.substring(startSpaceIndex, endSpaceIndex));
String remaining = nextToken.substring(endSpaceIndex + 1);
StringTokenizer qualifierTok = new StringTokenizer(remaining, ";");
while (qualifierTok.hasMoreTokens()) {
String nextQualifier = qualifierTok.nextToken();
int equalsIndex = nextQualifier.indexOf('=');
if (equalsIndex != -1) {
String nextQualifierKey = nextQualifier.substring(0, equalsIndex).trim();
String nextQualifierValue = nextQualifier.substring(equalsIndex+1, nextQualifier.length()).trim();
if (nextQualifierKey.equals("q")) {
try {
q = Float.parseFloat(nextQualifierValue);
q = Math.max(q, 0.0f);
} catch (NumberFormatException e) {
ourLog.debug("Invalid Accept header q value: {}", nextQualifierValue);
}
} }
} }
} }
@ -267,12 +300,46 @@ public class RestfulServerUtils {
bestQ = q; bestQ = q;
} }
} }
if (!",".equals(m.group(5))) {
break;
}
} }
//
//
//
//
// Matcher m = ACCEPT_HEADER_PATTERN.matcher(nextAcceptHeaderValue);
// float q = 1.0f;
// while (m.find()) {
// String contentTypeGroup = m.group(1);
// EncodingEnum encoding = Constants.FORMAT_VAL_TO_ENCODING.get(contentTypeGroup);
// if (encoding != null) {
//
// String name = m.group(3);
// String value = m.group(4);
// if (name != null && value != null) {
// if ("q".equals(name)) {
// try {
// q = Float.parseFloat(value);
// q = Math.max(q, 0.0f);
// } catch (NumberFormatException e) {
// ourLog.debug("Invalid Accept header q value: {}", value);
// }
// }
// }
// }
//
// if (encoding != null) {
// if (q > bestQ || (q == bestQ && encoding == thePrefer)) {
// retVal = encoding;
// bestQ = q;
// }
// }
//
// if (!",".equals(m.group(5))) {
// break;
// }
// }
//
} }
return retVal; return retVal;

View File

@ -212,6 +212,7 @@
<dependency> <dependency>
<groupId>javax.el</groupId> <groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId> <artifactId>javax.el-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.glassfish</groupId> <groupId>org.glassfish</groupId>

View File

@ -54,7 +54,6 @@ import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery; import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -306,7 +305,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return retVal; return retVal;
} }
private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, Root<? extends BaseResourceIndexedSearchParam> from, List<Predicate> codePredicates, IQueryParameterType nextOr) { private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, Root<? extends BaseResourceIndexedSearchParam> from, List<Predicate> codePredicates,
IQueryParameterType nextOr) {
boolean missingFalse = false; boolean missingFalse = false;
if (nextOr.getMissing() != null) { if (nextOr.getMissing() != null) {
if (nextOr.getMissing().booleanValue() == true) { if (nextOr.getMissing().booleanValue() == true) {
@ -320,7 +320,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return missingFalse; return missingFalse;
} }
private boolean addPredicateMissingFalseIfPresentForResourceLink(CriteriaBuilder theBuilder, String theParamName, Root<? extends ResourceLink> from, List<Predicate> codePredicates, IQueryParameterType nextOr) { private boolean addPredicateMissingFalseIfPresentForResourceLink(CriteriaBuilder theBuilder, String theParamName, Root<? extends ResourceLink> from, List<Predicate> codePredicates,
IQueryParameterType nextOr) {
boolean missingFalse = false; boolean missingFalse = false;
if (nextOr.getMissing() != null) { if (nextOr.getMissing() != null) {
if (nextOr.getMissing().booleanValue() == true) { if (nextOr.getMissing().booleanValue() == true) {
@ -1110,7 +1111,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
} }
} }
private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theFrom) { private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder,
From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theFrom) {
String rawSearchTerm; String rawSearchTerm;
if (theParameter instanceof TokenParam) { if (theParameter instanceof TokenParam) {
TokenParam id = (TokenParam) theParameter; TokenParam id = (TokenParam) theParameter;
@ -1129,7 +1131,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
} }
if (rawSearchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) { if (rawSearchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
throw new InvalidRequestException("Parameter[" + theParamName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm); throw new InvalidRequestException("Parameter[" + theParamName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed ("
+ ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm);
} }
String likeExpression = normalizeString(rawSearchTerm); String likeExpression = normalizeString(rawSearchTerm);
@ -1143,7 +1146,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return singleCode; return singleCode;
} }
private Predicate createPredicateToken(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> theFrom) { private Predicate createPredicateToken(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder,
From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> theFrom) {
String code; String code;
String system; String system;
if (theParameter instanceof TokenParam) { if (theParameter instanceof TokenParam) {
@ -1163,10 +1167,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
} }
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) { if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
throw new InvalidRequestException("Parameter[" + theParamName + "] has system (" + system.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system); throw new InvalidRequestException(
"Parameter[" + theParamName + "] has system (" + system.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system);
} }
if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) { if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
throw new InvalidRequestException("Parameter[" + theParamName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + code); throw new InvalidRequestException(
"Parameter[" + theParamName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + code);
} }
ArrayList<Predicate> singleCodePredicates = (new ArrayList<Predicate>()); ArrayList<Predicate> singleCodePredicates = (new ArrayList<Predicate>());
@ -1220,23 +1226,39 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
} }
String joinAttrName; String joinAttrName;
String sortAttrName; String[] sortAttrName;
switch (param.getParamType()) { switch (param.getParamType()) {
case STRING: case STRING:
joinAttrName = "myParamsString"; joinAttrName = "myParamsString";
sortAttrName = "myValueExact"; sortAttrName = new String[] { "myValueExact" };
break; break;
case DATE: case DATE:
joinAttrName = "myParamsDate"; joinAttrName = "myParamsDate";
sortAttrName = "myValueLow"; sortAttrName = new String[] { "myValueLow" };
break; break;
case REFERENCE: case REFERENCE:
joinAttrName = "myResourceLinks"; joinAttrName = "myResourceLinks";
sortAttrName = "myTargetResourcePid"; sortAttrName = new String[] { "myTargetResourcePid" };
break;
case TOKEN:
joinAttrName = "myParamsToken";
sortAttrName = new String[] { "mySystem", "myValue" };
break;
case NUMBER:
joinAttrName = "myParamsNumber";
sortAttrName = new String[] { "myValue" };
break;
case URI:
joinAttrName = "myParamsUri";
sortAttrName = new String[] { "myUri" };
break;
case QUANTITY:
joinAttrName = "myParamsQuantity";
sortAttrName = new String[] { "myValue" };
break; break;
default: default:
throw new NotImplementedException("This server does not support _sort specifications of type " + param.getParamType() + " - Can't serve _sort=" + theSort.getParamName()); throw new InvalidRequestException("This server does not support _sort specifications of type " + param.getParamType() + " - Can't serve _sort=" + theSort.getParamName());
} }
From<?, ?> stringJoin = theFrom.join(joinAttrName, JoinType.INNER); From<?, ?> stringJoin = theFrom.join(joinAttrName, JoinType.INNER);
@ -1251,10 +1273,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
// Predicate pn = theBuilder.isNull(stringJoin.get("myParamName")); // Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
// thePredicates.add(theBuilder.or(p, pn)); // thePredicates.add(theBuilder.or(p, pn));
if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) { for (String next : sortAttrName) {
theOrders.add(theBuilder.asc(stringJoin.get(sortAttrName))); if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) {
} else { theOrders.add(theBuilder.asc(stringJoin.get(next)));
theOrders.add(theBuilder.desc(stringJoin.get(sortAttrName))); } else {
theOrders.add(theBuilder.desc(stringJoin.get(next)));
}
} }
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates); createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates);
@ -1335,7 +1359,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
if (isNotBlank(theResource.getId().getIdPart())) { if (isNotBlank(theResource.getId().getIdPart())) {
if (isValidPid(theResource.getId())) { if (isValidPid(theResource.getId())) {
throw new UnprocessableEntityException("This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID"); throw new UnprocessableEntityException(
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
} }
createForcedIdIfNeeded(entity, theResource.getId()); createForcedIdIfNeeded(entity, theResource.getId());
@ -1869,7 +1894,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
if (entity == null) { if (entity == null) {
if (theId.hasVersionIdPart()) { if (theId.hasVersionIdPart()) {
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class); TypedQuery<ResourceHistoryTable> q = myEntityManager
.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
q.setParameter("RID", pid); q.setParameter("RID", pid);
q.setParameter("RTYP", myResourceName); q.setParameter("RTYP", myResourceName);
q.setParameter("RVER", Long.parseLong(theId.getVersionIdPart())); q.setParameter("RVER", Long.parseLong(theId.getVersionIdPart()));
@ -2047,7 +2073,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
revIncludedPids = new HashSet<Long>(); revIncludedPids = new HashSet<Long>();
} }
ourLog.info("Search returned PIDs: {}", pids); ourLog.debug("Search returned PIDs: {}", pids);
final int totalCount = pids.size(); final int totalCount = pids.size();
@ -2263,8 +2289,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
} }
/** /**
* If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to * If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to share the same value.
* share the same value.
*/ */
public void setSecondaryPrimaryKeyParamName(String theSecondaryPrimaryKeyParamName) { public void setSecondaryPrimaryKeyParamName(String theSecondaryPrimaryKeyParamName) {
mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName; mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName;
@ -2397,7 +2422,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
} }
if (resourceId.hasResourceType() && !resourceId.getResourceType().equals(getResourceName())) { if (resourceId.hasResourceType() && !resourceId.getResourceType().equals(getResourceName())) {
throw new UnprocessableEntityException("Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]"); throw new UnprocessableEntityException(
"Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
} }
// Notify interceptors // Notify interceptors
@ -2444,12 +2470,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
String sourceId = link.getSourceResource().getIdDt().toUnqualifiedVersionless().getValue(); String sourceId = link.getSourceResource().getIdDt().toUnqualifiedVersionless().getValue();
String sourcePath = link.getSourcePath(); String sourcePath = link.getSourcePath();
throw new PreconditionFailedException("Unable to delete " + targetId + " because at least one resource has a reference to this resource. First reference found was resource " + sourceId + " in path " + sourcePath); throw new PreconditionFailedException(
"Unable to delete " + targetId + " because at least one resource has a reference to this resource. First reference found was resource " + sourceId + " in path " + sourcePath);
} }
private void validateResourceType(BaseHasResource entity) { private void validateResourceType(BaseHasResource entity) {
if (!myResourceName.equals(entity.getResourceType())) { if (!myResourceName.equals(entity.getResourceType())) {
throw new ResourceNotFoundException("Resource with ID " + entity.getIdDt().getIdPart() + " exists but it is not of type " + myResourceName + ", found resource of type " + entity.getResourceType()); throw new ResourceNotFoundException(
"Resource with ID " + entity.getIdDt().getIdPart() + " exists but it is not of type " + myResourceName + ", found resource of type " + entity.getResourceType());
} }
} }

View File

@ -32,6 +32,7 @@ import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
@ -49,6 +50,7 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
@SequenceGenerator(name = "RES_HISTORY_PID", sequenceName = "RES_HISTORY_PID")
@Column(name = "PID") @Column(name = "PID")
private Long myId; private Long myId;

View File

@ -57,6 +57,7 @@ import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt; import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.ConceptMap;
import ca.uhn.fhir.model.dstu2.resource.Device; import ca.uhn.fhir.model.dstu2.resource.Device;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport; import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Encounter; import ca.uhn.fhir.model.dstu2.resource.Encounter;
@ -87,6 +88,7 @@ import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.QuantityParam; import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.IBundleProvider;
@ -149,6 +151,38 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
return retVal; return retVal;
} }
@Test
public void testCantSearchForDeletedResourceByLanguageOrTag() {
String methodName = "testCantSearchForDeletedResourceByLanguageOrTag";
Organization org = new Organization();
org.setLanguage(new CodeDt("EN_ca"));
org.setName(methodName);
TagList tl = new TagList();
tl.add(new Tag(methodName, methodName));
ResourceMetadataKeyEnum.TAG_LIST.put(org, tl);
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add("_language", new StringParam("EN_ca"));
assertEquals(1, myOrganizationDao.search(map).size());
map = new SearchParameterMap();
map.add("_tag", new TokenParam(methodName, methodName));
assertEquals(1, myOrganizationDao.search(map).size());
myOrganizationDao.delete(orgId);
map = new SearchParameterMap();
map.add("_language", new StringParam("EN_ca"));
assertEquals(0, myOrganizationDao.search(map).size());
map = new SearchParameterMap();
map.add("_tag", new TokenParam(methodName, methodName));
assertEquals(0, myOrganizationDao.search(map).size());
}
@Test @Test
public void testChoiceParamConcept() { public void testChoiceParamConcept() {
Observation o1 = new Observation(); Observation o1 = new Observation();
@ -163,71 +197,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
} }
} }
@Test
public void testCreateWithInvalid() {
Observation o1 = new Observation();
o1.getCode().addCoding().setSystem("foo").setCode("testChoiceParam01");
o1.setValue(new CodeableConceptDt("testChoiceParam01CCS", "testChoiceParam01CCV"));
IIdType id1 = myObservationDao.create(o1).getId();
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_CONCEPT, new TokenParam("testChoiceParam01CCS", "testChoiceParam01CCV"));
assertEquals(1, found.size());
assertEquals(id1, found.getResources(0, 1).get(0).getIdElement());
}
}
@Test
public void testCreateWithIllegalReference() {
Observation o1 = new Observation();
o1.getCode().addCoding().setSystem("foo").setCode("testChoiceParam01");
IIdType id1 = myObservationDao.create(o1).getId().toUnqualifiedVersionless();
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(id1);
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Invalid reference found at path 'Patient.managingOrganization'. Resource type 'Observation' is not valid for this path", e.getMessage());
}
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(new IdDt("Organization", id1.getIdPart()));
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Resource contains reference to Organization/" + id1.getIdPart() + " but resource with ID "+ id1.getIdPart()+" is actually of type Observation", e.getMessage());
}
// Now with a forced ID
o1 = new Observation();
o1.setId("testCreateWithIllegalReference");
o1.getCode().addCoding().setSystem("foo").setCode("testChoiceParam01");
id1 = myObservationDao.update(o1).getId().toUnqualifiedVersionless();
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(id1);
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Invalid reference found at path 'Patient.managingOrganization'. Resource type 'Observation' is not valid for this path", e.getMessage());
}
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(new IdDt("Organization", id1.getIdPart()));
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Resource contains reference to Organization/testCreateWithIllegalReference but resource with ID testCreateWithIllegalReference is actually of type Observation", e.getMessage());
}
}
@Test @Test
public void testChoiceParamDate() { public void testChoiceParamDate() {
Observation o2 = new Observation(); Observation o2 = new Observation();
@ -305,8 +274,8 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
@Test @Test
public void testCreateOperationOutcome() { public void testCreateOperationOutcome() {
/* /*
* If any of this ever fails, it means that one of the OperationOutcome issue severity codes has changed code * 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
* value across versions. We store the string as a constant, so something will need to be fixed. * be fixed.
*/ */
assertEquals(org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity.ERROR.toCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR); 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.dstu.valueset.IssueSeverityEnum.ERROR.getCode(), BaseHapiFhirResourceDao.OO_SEVERITY_ERROR);
@ -433,6 +402,71 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
} }
@Test
public void testCreateWithIllegalReference() {
Observation o1 = new Observation();
o1.getCode().addCoding().setSystem("foo").setCode("testChoiceParam01");
IIdType id1 = myObservationDao.create(o1).getId().toUnqualifiedVersionless();
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(id1);
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Invalid reference found at path 'Patient.managingOrganization'. Resource type 'Observation' is not valid for this path", e.getMessage());
}
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(new IdDt("Organization", id1.getIdPart()));
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Resource contains reference to Organization/" + id1.getIdPart() + " but resource with ID " + id1.getIdPart() + " is actually of type Observation", e.getMessage());
}
// Now with a forced ID
o1 = new Observation();
o1.setId("testCreateWithIllegalReference");
o1.getCode().addCoding().setSystem("foo").setCode("testChoiceParam01");
id1 = myObservationDao.update(o1).getId().toUnqualifiedVersionless();
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(id1);
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Invalid reference found at path 'Patient.managingOrganization'. Resource type 'Observation' is not valid for this path", e.getMessage());
}
try {
Patient p = new Patient();
p.getManagingOrganization().setReference(new IdDt("Organization", id1.getIdPart()));
myPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Resource contains reference to Organization/testCreateWithIllegalReference but resource with ID testCreateWithIllegalReference is actually of type Observation", e.getMessage());
}
}
@Test
public void testCreateWithInvalid() {
Observation o1 = new Observation();
o1.getCode().addCoding().setSystem("foo").setCode("testChoiceParam01");
o1.setValue(new CodeableConceptDt("testChoiceParam01CCS", "testChoiceParam01CCV"));
IIdType id1 = myObservationDao.create(o1).getId();
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_CONCEPT, new TokenParam("testChoiceParam01CCS", "testChoiceParam01CCV"));
assertEquals(1, found.size());
assertEquals(id1, found.getResources(0, 1).get(0).getIdElement());
}
}
@Test @Test
public void testCreateWithInvalidReferenceFailsGracefully() { public void testCreateWithInvalidReferenceFailsGracefully() {
Patient patient = new Patient(); Patient patient = new Patient();
@ -627,6 +661,50 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
} }
@Test
public void testDeleteFailsIfIncomingLinks() {
String methodName = "testDeleteFailsIfIncomingLinks";
Organization org = new Organization();
org.setName(methodName);
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
Patient patient = new Patient();
patient.addName().addFamily(methodName);
patient.getManagingOrganization().setReference(orgId);
IIdType patId = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add("_id", new StringParam(orgId.getIdPart()));
map.addRevInclude(new Include("*"));
List<IIdType> found = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(found, contains(orgId, patId));
try {
myOrganizationDao.delete(orgId);
fail();
} catch (PreconditionFailedException e) {
assertThat(e.getMessage(), containsString("Unable to delete Organization/" + orgId.getIdPart()
+ " because at least one resource has a reference to this resource. First reference found was resource Patient/" + patId.getIdPart() + " in path Patient.managingOrganization"));
}
myPatientDao.delete(patId);
map = new SearchParameterMap();
map.add("_id", new StringParam(orgId.getIdPart()));
map.addRevInclude(new Include("*"));
found = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(found, contains(orgId));
myOrganizationDao.delete(orgId);
map = new SearchParameterMap();
map.add("_id", new StringParam(orgId.getIdPart()));
map.addRevInclude(new Include("*"));
found = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(found, empty());
}
@Test @Test
public void testDeleteResource() { public void testDeleteResource() {
int initialHistory = myPatientDao.history(null).size(); int initialHistory = myPatientDao.history(null).size();
@ -690,81 +768,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
} }
@Test
public void testCantSearchForDeletedResourceByLanguageOrTag() {
String methodName = "testCantSearchForDeletedResourceByLanguageOrTag";
Organization org = new Organization();
org.setLanguage(new CodeDt("EN_ca"));
org.setName(methodName);
TagList tl = new TagList();
tl.add(new Tag(methodName, methodName));
ResourceMetadataKeyEnum.TAG_LIST.put(org, tl);
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add("_language", new StringParam("EN_ca"));
assertEquals(1, myOrganizationDao.search(map).size());
map = new SearchParameterMap();
map.add("_tag", new TokenParam(methodName, methodName));
assertEquals(1, myOrganizationDao.search(map).size());
myOrganizationDao.delete(orgId);
map = new SearchParameterMap();
map.add("_language", new StringParam("EN_ca"));
assertEquals(0, myOrganizationDao.search(map).size());
map = new SearchParameterMap();
map.add("_tag", new TokenParam(methodName, methodName));
assertEquals(0, myOrganizationDao.search(map).size());
}
@Test
public void testDeleteFailsIfIncomingLinks() {
String methodName = "testDeleteFailsIfIncomingLinks";
Organization org = new Organization();
org.setName(methodName);
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
Patient patient = new Patient();
patient.addName().addFamily(methodName);
patient.getManagingOrganization().setReference(orgId);
IIdType patId = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add("_id", new StringParam(orgId.getIdPart()));
map.addRevInclude(new Include("*"));
List<IIdType> found = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(found, contains(orgId, patId));
try {
myOrganizationDao.delete(orgId);
fail();
} catch (PreconditionFailedException e) {
assertThat(e.getMessage(), containsString("Unable to delete Organization/" + orgId.getIdPart() + " because at least one resource has a reference to this resource. First reference found was resource Patient/" + patId.getIdPart() + " in path Patient.managingOrganization"));
}
myPatientDao.delete(patId);
map = new SearchParameterMap();
map.add("_id", new StringParam(orgId.getIdPart()));
map.addRevInclude(new Include("*"));
found = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(found, contains(orgId));
myOrganizationDao.delete(orgId);
map = new SearchParameterMap();
map.add("_id", new StringParam(orgId.getIdPart()));
map.addRevInclude(new Include("*"));
found = toUnqualifiedVersionlessIds(myOrganizationDao.search(map));
assertThat(found, empty());
}
@Test @Test
public void testDeleteThenUndelete() { public void testDeleteThenUndelete() {
Patient patient = new Patient(); Patient patient = new Patient();
@ -1033,7 +1036,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(0))); assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(0)));
assertEquals(BundleEntryTransactionMethodEnum.PUT, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) entries.get(0))); assertEquals(BundleEntryTransactionMethodEnum.PUT, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) entries.get(0)));
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(1))); assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(1)));
assertEquals(BundleEntryTransactionMethodEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) entries.get(1))); assertEquals(BundleEntryTransactionMethodEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) entries.get(1)));
@ -1874,6 +1877,18 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals(BundleEntrySearchModeEnum.INCLUDE, ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get((IResource) results.get(1))); assertEquals(BundleEntrySearchModeEnum.INCLUDE, ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get((IResource) results.get(1)));
} }
@Test()
public void testSortByComposite() {
SearchParameterMap pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_CODE_VALUE_CONCEPT));
try {
myObservationDao.search(pm);
fail();
} catch (InvalidRequestException e) {
assertEquals("This server does not support _sort specifications of type COMPOSITE - Can't serve _sort=code-value-concept", e.getMessage());
}
}
@Test @Test
public void testSortByDate() { public void testSortByDate() {
Patient p = new Patient(); Patient p = new Patient();
@ -1976,6 +1991,78 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertThat(actual, contains(id4, id3, id2, id1, idMethodName)); assertThat(actual, contains(id4, id3, id2, id1, idMethodName));
} }
@Test
public void testSortByNumber() {
String methodName = "testSortByNumber";
Encounter e1 = new Encounter();
e1.addIdentifier().setSystem("foo").setValue(methodName);
e1.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("min").setValue(4.0 * 24 * 60);
IIdType id1 = myEncounterDao.create(e1).getId().toUnqualifiedVersionless();
Encounter e3 = new Encounter();
e3.addIdentifier().setSystem("foo").setValue(methodName);
e3.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("year").setValue(3.0);
IIdType id3 = myEncounterDao.create(e3).getId().toUnqualifiedVersionless();
Encounter e2 = new Encounter();
e2.addIdentifier().setSystem("foo").setValue(methodName);
e2.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("year").setValue(2.0);
IIdType id2 = myEncounterDao.create(e2).getId().toUnqualifiedVersionless();
SearchParameterMap pm;
List<IIdType> actual;
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Encounter.SP_LENGTH));
actual = toUnqualifiedVersionlessIds(myEncounterDao.search(pm));
assertThat(actual, contains(id1, id2, id3));
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Encounter.SP_LENGTH, SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIds(myEncounterDao.search(pm));
assertThat(actual, contains(id3, id2, id1));
}
public void testSortByQuantity() {
Observation res;
res = new Observation();
res.setValue(new QuantityDt().setSystem("sys1").setCode("code1").setValue(2L));
IIdType id2 = myObservationDao.create(res).getId().toUnqualifiedVersionless();
res = new Observation();
res.setValue(new QuantityDt().setSystem("sys1").setCode("code1").setValue(1L));
IIdType id1 = myObservationDao.create(res).getId().toUnqualifiedVersionless();
res = new Observation();
res.setValue(new QuantityDt().setSystem("sys1").setCode("code1").setValue(3L));
IIdType id3 = myObservationDao.create(res).getId().toUnqualifiedVersionless();
res = new Observation();
res.setValue(new QuantityDt().setSystem("sys1").setCode("code1").setValue(4L));
IIdType id4 = myObservationDao.create(res).getId().toUnqualifiedVersionless();
SearchParameterMap pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_VALUE_QUANTITY));
List<IIdType> actual = toUnqualifiedVersionlessIds(myConceptMapDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id1, id2, id3, id4));
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_VALUE_QUANTITY, SortOrderEnum.ASC));
actual = toUnqualifiedVersionlessIds(myConceptMapDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id1, id2, id3, id4));
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_VALUE_QUANTITY, SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIds(myObservationDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id4, id3, id2, id1));
}
@Test @Test
public void testSortByReference() { public void testSortByReference() {
String methodName = "testSortByReference"; String methodName = "testSortByReference";
@ -2149,6 +2236,88 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertThat(names.subList(2, 4), contains("Giv2 Fam1", "Giv1 Fam1")); assertThat(names.subList(2, 4), contains("Giv2 Fam1", "Giv1 Fam1"));
} }
@Test
public void testSortByToken() {
String methodName = "testSortByToken";
Patient p;
p = new Patient();
p.addIdentifier().setSystem("urn:system2").setValue(methodName + "1");
IIdType id3 = myPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system1").setValue(methodName + "2");
IIdType id2 = myPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system1").setValue(methodName + "1");
IIdType id1 = myPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system2").setValue(methodName + "2");
IIdType id4 = myPatientDao.create(p).getId().toUnqualifiedVersionless();
SearchParameterMap pm;
List<IIdType> actual;
pm = new SearchParameterMap();
TokenOrListParam sp = new TokenOrListParam();
sp.addOr(new TokenParam("urn:system1", methodName + "1"));
sp.addOr(new TokenParam("urn:system1", methodName + "2"));
sp.addOr(new TokenParam("urn:system2", methodName + "1"));
sp.addOr(new TokenParam("urn:system2", methodName + "2"));
pm.add(Patient.SP_IDENTIFIER, sp);
pm.setSort(new SortSpec(Patient.SP_IDENTIFIER));
actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id1, id2, id3, id4));
pm = new SearchParameterMap();
sp = new TokenOrListParam();
sp.addOr(new TokenParam("urn:system1", methodName + "1"));
sp.addOr(new TokenParam("urn:system1", methodName + "2"));
sp.addOr(new TokenParam("urn:system2", methodName + "1"));
sp.addOr(new TokenParam("urn:system2", methodName + "2"));
pm.add(Patient.SP_IDENTIFIER, sp);
pm.setSort(new SortSpec(Patient.SP_IDENTIFIER, SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIds(myPatientDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id4, id3, id2, id1));
}
public void testSortByUri() {
ConceptMap res = new ConceptMap();
res.addElement().addTarget().addDependsOn().setElement("http://foo2");
IIdType id2 = myConceptMapDao.create(res).getId().toUnqualifiedVersionless();
res = new ConceptMap();
res.addElement().addTarget().addDependsOn().setElement("http://foo1");
IIdType id1 = myConceptMapDao.create(res).getId().toUnqualifiedVersionless();
res = new ConceptMap();
res.addElement().addTarget().addDependsOn().setElement("http://bar3");
IIdType id3 = myConceptMapDao.create(res).getId().toUnqualifiedVersionless();
res = new ConceptMap();
res.addElement().addTarget().addDependsOn().setElement("http://bar4");
IIdType id4 = myConceptMapDao.create(res).getId().toUnqualifiedVersionless();
SearchParameterMap pm = new SearchParameterMap();
pm.setSort(new SortSpec(ConceptMap.SP_DEPENDSON));
List<IIdType> actual = toUnqualifiedVersionlessIds(myConceptMapDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id1, id2, id3, id4));
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Encounter.SP_LENGTH, SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIds(myConceptMapDao.search(pm));
assertEquals(4, actual.size());
assertThat(actual, contains(id4, id3, id2, id1));
}
@Test @Test
public void testStoreUnversionedResources() { public void testStoreUnversionedResources() {
Organization o1 = new Organization(); Organization o1 = new Organization();

View File

@ -92,7 +92,6 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test { public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2Test.class);
// private static JpaConformanceProvider ourConfProvider; // private static JpaConformanceProvider ourConfProvider;
@ -154,7 +153,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
assertThat(toIdListUnqualifiedVersionless(found), containsInAnyOrder(id1)); assertThat(toIdListUnqualifiedVersionless(found), containsInAnyOrder(id1));
} }
@Test @Test
public void testBundleCreate() throws Exception { public void testBundleCreate() throws Exception {
IGenericClient client = ourClient; IGenericClient client = ourClient;
@ -209,16 +208,16 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
@Test @Test
public void testCreateWithForcedId() throws IOException { public void testCreateWithForcedId() throws IOException {
String methodName = "testCreateWithForcedId"; String methodName = "testCreateWithForcedId";
Patient p = new Patient(); Patient p = new Patient();
p.addName().addFamily(methodName); p.addName().addFamily(methodName);
p.setId(methodName); p.setId(methodName);
IIdType optId = ourClient.update().resource(p).execute().getId(); IIdType optId = ourClient.update().resource(p).execute().getId();
assertEquals(methodName, optId.getIdPart()); assertEquals(methodName, optId.getIdPart());
assertEquals("1", optId.getVersionIdPart()); assertEquals("1", optId.getVersionIdPart());
} }
@Test @Test
public void testCreateQuestionnaireResponseWithValidation() throws IOException { public void testCreateQuestionnaireResponseWithValidation() throws IOException {
ValueSet options = new ValueSet(); ValueSet options = new ValueSet();
@ -428,8 +427,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
} }
/* /*
* Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to * 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..
* make sure that works too..
*/ */
Socket sock = new Socket(); Socket sock = new Socket();
sock.setSoTimeout(3000); sock.setSoTimeout(3000);
@ -701,7 +699,8 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
patient.setId(id); patient.setId(id);
ourClient.update().resource(patient).execute(); ourClient.update().resource(patient).execute();
ca.uhn.fhir.model.dstu2.resource.Bundle history = ourClient.history().onInstance(id).andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class).prettyPrint().summaryMode(SummaryEnum.DATA).execute(); ca.uhn.fhir.model.dstu2.resource.Bundle history = ourClient.history().onInstance(id).andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class).prettyPrint().summaryMode(SummaryEnum.DATA)
.execute();
assertEquals(3, history.getEntry().size()); assertEquals(3, history.getEntry().size());
assertEquals(id.withVersion("3"), history.getEntry().get(0).getResource().getId()); assertEquals(id.withVersion("3"), history.getEntry().get(0).getResource().getId());
assertEquals(1, ((Patient) history.getEntry().get(0).getResource()).getName().size()); assertEquals(1, ((Patient) history.getEntry().get(0).getResource()).getName().size());
@ -752,7 +751,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
Patient p = new Patient(); Patient p = new Patient();
p.addName().addFamily("testMetaAddInvalid"); p.addName().addFamily("testMetaAddInvalid");
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless(); IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
//@formatter:off //@formatter:off
String input = "<Parameters>\n" + String input = "<Parameters>\n" +
" <meta>\n" + " <meta>\n" +
@ -764,7 +763,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
" </meta>\n" + " </meta>\n" +
"</Parameters>"; "</Parameters>";
//@formatter:on //@formatter:on
HttpPost post = new HttpPost(ourServerBase + "/Patient/" + id.getIdPart() + "/$meta-add"); HttpPost post = new HttpPost(ourServerBase + "/Patient/" + id.getIdPart() + "/$meta-add");
post.setEntity(new StringEntity(input, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); post.setEntity(new StringEntity(input, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
CloseableHttpResponse response = ourHttpClient.execute(post); CloseableHttpResponse response = ourHttpClient.execute(post);
@ -790,7 +789,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
} }
} }
@Test @Test
public void testMetaOperations() throws Exception { public void testMetaOperations() throws Exception {
String methodName = "testMetaOperations"; String methodName = "testMetaOperations";
@ -948,7 +947,8 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01"); p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01");
IdDt p1Id = (IdDt) ourClient.create().resource(p1).execute().getId(); 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(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart()); assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());
@ -1152,6 +1152,18 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
assertEquals(BundleEntrySearchModeEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE)); assertEquals(BundleEntrySearchModeEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
} }
@Test(expected = InvalidRequestException.class)
public void testSearchWithInvalidSort() throws Exception {
//@formatter:off
Bundle found = ourClient
.search()
.forResource(Observation.class)
.sort().ascending(Observation.CODE_VALUE_QUANTITY) // composite sort not supported yet
.prettyPrint()
.execute();
//@formatter:on
}
@Test @Test
public void testSearchWithMissing() throws Exception { public void testSearchWithMissing() throws Exception {
ourLog.info("Starting testSearchWithMissing"); ourLog.info("Starting testSearchWithMissing");

View File

@ -1,8 +1,10 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.junit.Assert.*; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -11,7 +13,6 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -198,11 +199,31 @@ public class ServerFeaturesTest {
@Test @Test
public void testAcceptHeaderWithPrettyPrint() throws Exception { public void testAcceptHeaderWithPrettyPrint() throws Exception {
HttpGet httpGet;
CloseableHttpResponse status;
String responseContent;
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", Constants.CT_FHIR_JSON + "; pretty=true; q=1.0, " + Constants.CT_FHIR_XML + "; pretty=true; q=0.9");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, (containsString("\"identifier\":")));
assertThat(responseContent, (containsString(",\n")));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", Constants.CT_FHIR_JSON + "; pretty=true" + ", " + Constants.CT_FHIR_XML + "; pretty=true");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, not(containsString("\"identifier\":")));
assertThat(responseContent, (containsString(">\n")));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", Constants.CT_FHIR_XML + "; pretty=true"); httpGet.addHeader("Accept", Constants.CT_FHIR_XML + "; pretty=true");
CloseableHttpResponse status = ourClient.execute(httpGet); status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, StringContains.containsString("<identifier>\n ")); assertThat(responseContent, StringContains.containsString("<identifier>\n "));
@ -216,13 +237,12 @@ public class ServerFeaturesTest {
assertThat(responseContent, StringContains.containsString("\",\n")); assertThat(responseContent, StringContains.containsString("\",\n"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", Constants.CT_FHIR_JSON + "; pretty=true" + ", " + Constants.CT_FHIR_XML + "; pretty=true"); httpGet.addHeader("Accept", Constants.CT_FHIR_JSON + "; pretty=true; q=1.0" + ", " + Constants.CT_FHIR_XML + "; pretty=true; q=0.9");
status = ourClient.execute(httpGet); status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent()); responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, (containsString("\"identifier\":")));
assertThat(responseContent, StringContains.containsString("\"identifier\":")); assertThat(responseContent, (containsString(",\n")));
} }
@Test @Test

View File

@ -0,0 +1,117 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import ca.uhn.fhir.util.PortUtil;
public class ServerWithResponseHighlightingInterceptorExceptionTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerWithResponseHighlightingInterceptorExceptionTest.class);
private static CloseableHttpClient ourClient;
private static int ourPort;
private static Server ourServer;
private static FhirContext ourCtx = FhirContext.forDstu2();
private static RestfulServer ourServlet;
@Test
public void testExpectedException() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<diagnostics value=\"AAABBB\"/>"));
}
@Test
public void testUnexpectedException() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(500, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<diagnostics value=\"Failed to call access method\"/>"));
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
ourServlet = new RestfulServer(ourCtx);
ourServlet.setFhirContext(ourCtx);
ourServlet.setResourceProviders(patientProvider);
ourServlet.registerInterceptor(new ResponseHighlighterInterceptor());
ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Read
public Patient read(@IdParam IdDt theId) {
throw new InvalidRequestException("AAABBB");
}
@Search
public Patient search(@RequiredParam(name="identifier") TokenParam theToken) {
throw new Error("AAABBB");
}
@Override
public Class<? extends IResource> getResourceType() {
return Patient.class;
}
}
}

View File

@ -70,6 +70,11 @@
In server, if a client request is received and it has an Accept header indicating In server, if a client request is received and it has an Accept header indicating
that it supports both XML and JSON with equal weight, the server's default is used instead of the first entry in the list. that it supports both XML and JSON with equal weight, the server's default is used instead of the first entry in the list.
</action> </action>
<action type="add">
JPA server now supports searching with sort by token, quantity,
number and URI (previously only string, date, _id and _lastUpdated
were supported)
</action>
</release> </release>
<release version="1.2" date="2015-09-18"> <release version="1.2" date="2015-09-18">
<action type="add"> <action type="add">