Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
jamesagnew 2015-09-26 08:49:37 -04:00
commit f818a3b478
17 changed files with 716 additions and 233 deletions

View File

@ -245,7 +245,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequest);
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest());
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest(), theServer.getDefaultResponseEncoding());
// Is this request coming from a browser
String uaHeader = theRequest.getServletRequest().getHeader("user-agent");

View File

@ -54,7 +54,7 @@ public class Constants {
public static final String FORMAT_XML = "xml";
public static final String HEADER_ACCEPT = "Accept";
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
public static final String HEADER_ACCEPT_VALUE_ALL = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_XML + ";q=1.0";
public static final String HEADER_ACCEPT_VALUE_ALL = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_JSON + ";q=1.0";
public static final String HEADER_ALLOW = "Allow";
public static final String HEADER_AUTHORIZATION = "Authorization";
public static final String HEADER_AUTHORIZATION_VALPREFIX_BASIC = "Basic ";

View File

@ -491,7 +491,7 @@ public class RestfulServer extends HttpServlet {
int start = Math.min(offsetI, resultList.size() - 1);
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest());
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest(), getDefaultResponseEncoding());
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(this, theRequest);
boolean requestIsBrowser = requestIsBrowser(theRequest.getServletRequest());
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequest);

View File

@ -214,7 +214,11 @@ public class RestfulServerUtils {
return retVal;
}
public static EncodingEnum determineResponseEncodingNoDefault(HttpServletRequest theReq) {
/**
* Returns null if the request doesn't express that it wants FHIR. If it expresses that it wants
* XML and JSON equally, returns thePrefer.
*/
public static EncodingEnum determineResponseEncodingNoDefault(HttpServletRequest theReq, EncodingEnum thePrefer) {
String[] format = theReq.getParameterValues(Constants.PARAM_FORMAT);
if (format != null) {
for (String nextFormat : format) {
@ -236,37 +240,106 @@ public class RestfulServerUtils {
EncodingEnum retVal = null;
while (acceptValues.hasMoreElements()) {
String nextAcceptHeaderValue = acceptValues.nextElement();
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) {
StringTokenizer tok = new StringTokenizer(nextAcceptHeaderValue, ",");
while (tok.hasMoreTokens()) {
String nextToken = tok.nextToken();
int startSpaceIndex = -1;
for (int i = 0; i < nextToken.length(); i++) {
if (nextToken.charAt(i) != ' ') {
startSpaceIndex = i;
break;
}
}
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 (startSpaceIndex == -1) {
continue;
}
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);
}
}
}
}
}
if (q > bestQ && encoding != null) {
retVal = encoding;
bestQ = q;
if (encoding != null) {
if (q > bestQ || (q == bestQ && encoding == thePrefer)) {
retVal = encoding;
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;
@ -278,7 +351,7 @@ public class RestfulServerUtils {
* Determine whether a response should be given in JSON or XML format based on the incoming HttpServletRequest's <code>"_format"</code> parameter and <code>"Accept:"</code> HTTP header.
*/
public static EncodingEnum determineResponseEncodingWithDefault(RestfulServer theServer, HttpServletRequest theReq) {
EncodingEnum retVal = determineResponseEncodingNoDefault(theReq);
EncodingEnum retVal = determineResponseEncodingNoDefault(theReq, theServer.getDefaultResponseEncoding());
if (retVal == null) {
retVal = theServer.getDefaultResponseEncoding();
}
@ -328,10 +401,7 @@ public class RestfulServerUtils {
public static IParser getNewParser(FhirContext theContext, RequestDetails theRequestDetails) {
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
if (responseEncoding == null) {
responseEncoding = theRequestDetails.getServer().getDefaultResponseEncoding();
}
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequestDetails.getServer(), theRequestDetails.getServletRequest());
IParser parser;
switch (responseEncoding) {
case JSON:
@ -472,8 +542,7 @@ public class RestfulServerUtils {
theHttpResponse.setStatus(200);
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
responseEncoding = responseEncoding != null ? responseEncoding : theServer.getDefaultResponseEncoding();
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theServer, theRequestDetails.getServletRequest());
if (theRequestIsBrowser && theServer.isUseBrowserFriendlyContentTypes()) {
theHttpResponse.setContentType(responseEncoding.getBrowserFriendlyBundleContentType());
@ -502,7 +571,7 @@ public class RestfulServerUtils {
theHttpResponse.setStatus(stausCode);
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest(), theServer.getDefaultResponseEncoding());
String serverBase = theRequestDetails.getFhirServerBase();
if (theAddContentLocationHeader && theResource.getIdElement() != null && theResource.getIdElement().hasIdPart() && isNotBlank(serverBase)) {

View File

@ -198,7 +198,7 @@ public class LoggingInterceptor extends InterceptorAdapter {
} else if (theKey.startsWith("remoteAddr")) {
return StringUtils.defaultString(myRequest.getRemoteAddr());
} else if (theKey.equals("responseEncodingNoDefault")) {
EncodingEnum encoding = RestfulServerUtils.determineResponseEncodingNoDefault(myRequest);
EncodingEnum encoding = RestfulServerUtils.determineResponseEncodingNoDefault(myRequest, myRequestDetails.getServer().getDefaultResponseEncoding());
if (encoding != null) {
return encoding.name();
} else {

View File

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

View File

@ -54,7 +54,6 @@ import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -306,7 +305,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
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;
if (nextOr.getMissing() != null) {
if (nextOr.getMissing().booleanValue() == true) {
@ -320,7 +320,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
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;
if (nextOr.getMissing() != null) {
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;
if (theParameter instanceof TokenParam) {
TokenParam id = (TokenParam) theParameter;
@ -1129,7 +1131,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
}
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);
@ -1143,7 +1146,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
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 system;
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) {
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) {
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>());
@ -1220,23 +1226,39 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
}
String joinAttrName;
String sortAttrName;
String[] sortAttrName;
switch (param.getParamType()) {
case STRING:
joinAttrName = "myParamsString";
sortAttrName = "myValueExact";
sortAttrName = new String[] { "myValueExact" };
break;
case DATE:
joinAttrName = "myParamsDate";
sortAttrName = "myValueLow";
sortAttrName = new String[] { "myValueLow" };
break;
case REFERENCE:
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;
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);
@ -1251,10 +1273,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
// Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
// thePredicates.add(theBuilder.or(p, pn));
if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) {
theOrders.add(theBuilder.asc(stringJoin.get(sortAttrName)));
} else {
theOrders.add(theBuilder.desc(stringJoin.get(sortAttrName)));
for (String next : sortAttrName) {
if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) {
theOrders.add(theBuilder.asc(stringJoin.get(next)));
} else {
theOrders.add(theBuilder.desc(stringJoin.get(next)));
}
}
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 (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());
@ -1869,7 +1894,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
if (entity == null) {
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("RTYP", myResourceName);
q.setParameter("RVER", Long.parseLong(theId.getVersionIdPart()));
@ -2047,7 +2073,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
revIncludedPids = new HashSet<Long>();
}
ourLog.info("Search returned PIDs: {}", pids);
ourLog.debug("Search returned PIDs: {}", pids);
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
* share the same value.
* 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.
*/
public void setSecondaryPrimaryKeyParamName(String theSecondaryPrimaryKeyParamName) {
mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName;
@ -2397,7 +2422,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
}
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
@ -2444,12 +2470,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
String sourceId = link.getSourceResource().getIdDt().toUnqualifiedVersionless().getValue();
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) {
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.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@ -49,6 +50,7 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@SequenceGenerator(name = "RES_HISTORY_PID", sequenceName = "RES_HISTORY_PID")
@Column(name = "PID")
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.ResourceReferenceDt;
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.DiagnosticReport;
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.ReferenceParam;
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.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
@ -149,6 +151,38 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
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
public void testChoiceParamConcept() {
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
public void testChoiceParamDate() {
Observation o2 = new Observation();
@ -305,8 +274,8 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
@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.
* 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);
@ -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
public void testCreateWithInvalidReferenceFailsGracefully() {
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
public void testDeleteResource() {
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
public void testDeleteThenUndelete() {
Patient patient = new Patient();
@ -1874,6 +1877,18 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
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
public void testSortByDate() {
Patient p = new Patient();
@ -1976,6 +1991,78 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
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
public void testSortByReference() {
String methodName = "testSortByReference";
@ -2149,6 +2236,88 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
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
public void testStoreUnversionedResources() {
Organization o1 = new Organization();

View File

@ -93,7 +93,6 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2Test.class);
// private static JpaConformanceProvider ourConfProvider;
private void checkParamMissing(String paramName) throws IOException, ClientProtocolException {
@ -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
* 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);
@ -701,7 +699,8 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
patient.setId(id);
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(id.withVersion("3"), history.getEntry().get(0).getResource().getId());
assertEquals(1, ((Patient) history.getEntry().get(0).getResource()).getName().size());
@ -948,7 +947,8 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
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());
@ -1152,6 +1152,18 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
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
public void testSearchWithMissing() throws Exception {
ourLog.info("Starting testSearchWithMissing");

View File

@ -1,7 +1,5 @@
package ca.uhn.fhirtest;
import java.sql.DriverManager;
import org.apache.derby.drda.NetworkServerControl;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

View File

@ -18,7 +18,7 @@
<util:list id="myServerInterceptors">
<ref bean="myLoggingInterceptor"/>
<ref bean="mySubscriptionSecurityInterceptor"/>
<!-- <ref bean="mySubscriptionSecurityInterceptor"/> -->
</util:list>
<!--
@ -44,7 +44,9 @@
<bean id="dbServer" class="ca.uhn.fhirtest.DerbyNetworkServer">
</bean>
<!--
<bean id="mySubscriptionSecurityInterceptor" class="ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor"/>
-->
<!--
Do some fancy logging to create a nice access log that has details

View File

@ -36,9 +36,6 @@ import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.util.PortUtil;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class DefaultEncodingTest {
private static CloseableHttpClient ourClient;
@ -47,6 +44,59 @@ public class DefaultEncodingTest {
private static final FhirContext ourCtx = FhirContext.forDstu1();
private static RestfulServer ourRestfulServer;
@Test
public void testHonoursAcceptHeader() throws Exception {
ourRestfulServer.setDefaultPrettyPrint(false);
ourRestfulServer.setDefaultResponseEncoding(EncodingEnum.JSON);
HttpGet httpGet;
HttpResponse status;
String responseContent;
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/json");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/json+fhir");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/json+fhir, application/xml+fhir");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/xml+fhir, application/json+fhir");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/xml+fhir; q=0.9, application/json+fhir; q=1.0");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, containsString("\"identifier\":"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader("Accept", "application/xml+fhir; q=1.0, application/json+fhir; q=0.9");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, not(containsString("\"identifier\":")));
}
@Test
public void testReadWithDefaultJsonPretty() throws Exception {
ourRestfulServer.setDefaultPrettyPrint(true);

View File

@ -1,8 +1,10 @@
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.HashMap;
import java.util.List;
@ -11,7 +13,6 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
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;
@ -198,11 +199,31 @@ public class ServerFeaturesTest {
@Test
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");
CloseableHttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertThat(responseContent, StringContains.containsString("<identifier>\n "));
@ -216,13 +237,12 @@ public class ServerFeaturesTest {
assertThat(responseContent, StringContains.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");
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, StringContains.containsString("\"identifier\":"));
assertThat(responseContent, (containsString("\"identifier\":")));
assertThat(responseContent, (containsString(",\n")));
}
@Test

View File

@ -220,9 +220,11 @@ public class GenericClientDstu2Test {
assertEquals("http://"+methodName+".example.com/fhir/metadata?_format=json", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), not(containsString(Constants.CT_FHIR_XML)));
assertEquals("http://"+methodName+".example.com/fhir/Patient/123?_format=json", capt.getAllValues().get(1).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), not(containsString(Constants.CT_FHIR_XML)));
}
@Test
@ -259,9 +261,13 @@ public class GenericClientDstu2Test {
assertEquals("http://"+methodName+".example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
assertEquals("http://"+methodName+".example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length);
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
}

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

@ -66,6 +66,15 @@
to a resource that is not valid in the location it is found in (e.g. points to Patient/123 but
the field supposed to reference an Organization). Thanks to Bill de Beaubien for reporting!
</action>
<action type="fix">
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.
</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 version="1.2" date="2015-09-18">
<action type="add">