JPA server now correctly suppresses contents of deleted resources

in history
This commit is contained in:
jamesagnew 2015-09-12 09:45:12 -04:00
parent e2bc9336f9
commit 48ee2cbee8
9 changed files with 381 additions and 179 deletions

View File

@ -19,8 +19,7 @@ package ca.uhn.fhir.model.api;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.Serializable;
import java.util.ArrayList;
@ -35,7 +34,6 @@ import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -74,6 +72,8 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<InstantDt> DELETED_AT = new ResourceMetadataKeyEnum<InstantDt>("DELETED_AT") {
private static final long serialVersionUID = 1L;
@Override
public InstantDt get(IResource theResource) {
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), DELETED_AT);
@ -96,6 +96,8 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<DecimalDt> ENTRY_SCORE = new ResourceMetadataKeyEnum<DecimalDt>("ENTRY_SCORE") {
private static final long serialVersionUID = 1L;
@Override
public DecimalDt get(IResource theResource) {
return getDecimalFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SCORE);
@ -119,6 +121,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<BundleEntrySearchModeEnum> ENTRY_SEARCH_MODE = new ResourceMetadataKeyEnum<BundleEntrySearchModeEnum>("ENTRY_SEARCH_MODE") {
private static final long serialVersionUID = 1L;
@Override
public BundleEntrySearchModeEnum get(IResource theResource) {
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SEARCH_MODE, BundleEntrySearchModeEnum.class, BundleEntrySearchModeEnum.VALUESET_BINDER);
@ -144,6 +147,8 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
*/
public static final ResourceMetadataKeyEnum<BundleEntryTransactionMethodEnum> ENTRY_TRANSACTION_METHOD = new ResourceMetadataKeyEnum<BundleEntryTransactionMethodEnum>(
"ENTRY_TRANSACTION_OPERATION") {
private static final long serialVersionUID = 1L;
@Override
public BundleEntryTransactionMethodEnum get(IResource theResource) {
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_TRANSACTION_METHOD, BundleEntryTransactionMethodEnum.class,
@ -165,6 +170,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<String> LINK_ALTERNATE = new ResourceMetadataKeyEnum<String>("LINK_ALTERNATE") {
private static final long serialVersionUID = 1L;
@Override
public String get(IResource theResource) {
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_ALTERNATE);
@ -185,6 +191,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<String> LINK_SEARCH = new ResourceMetadataKeyEnum<String>("LINK_SEARCH") {
private static final long serialVersionUID = 1L;
@Override
public String get(IResource theResource) {
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_SEARCH);
@ -203,6 +210,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<IdDt> PREVIOUS_ID = new ResourceMetadataKeyEnum<IdDt>("PREVIOUS_ID") {
private static final long serialVersionUID = 1L;
@Override
public IdDt get(IResource theResource) {
return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PREVIOUS_ID);
@ -222,6 +230,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<List<IdDt>> PROFILES = new ResourceMetadataKeyEnum<List<IdDt>>("PROFILES") {
private static final long serialVersionUID = 1L;
@Override
public List<IdDt> get(IResource theResource) {
return getIdListFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PROFILES);
@ -245,6 +254,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* @see InstantDt
*/
public static final ResourceMetadataKeyEnum<InstantDt> PUBLISHED = new ResourceMetadataKeyEnum<InstantDt>("PUBLISHED") {
private static final long serialVersionUID = 1L;
@Override
public InstantDt get(IResource theResource) {
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PUBLISHED);
@ -257,6 +267,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
};
public static final ResourceMetadataKeyEnum<List<BaseCodingDt>> SECURITY_LABELS = new ResourceMetadataKeyEnum<List<BaseCodingDt>>("SECURITY_LABELS") {
private static final long serialVersionUID = 1L;
@Override
public List<BaseCodingDt> get(IResource resource) {
Object obj = resource.getResourceMetadata().get(SECURITY_LABELS);
@ -264,6 +275,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
return null;
} else {
try {
@SuppressWarnings("unchecked")
List<BaseCodingDt> securityLabels = (List<BaseCodingDt>) obj;
if (securityLabels.isEmpty())
return null;
@ -294,6 +306,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* @see TagList
*/
public static final ResourceMetadataKeyEnum<TagList> TAG_LIST = new ResourceMetadataKeyEnum<TagList>("TAG_LIST") {
private static final long serialVersionUID = 1L;
@Override
public TagList get(IResource theResource) {
Object retValObj = theResource.getResourceMetadata().get(TAG_LIST);
@ -323,6 +336,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<String> TITLE = new ResourceMetadataKeyEnum<String>("TITLE") {
private static final long serialVersionUID = 1L;
@Override
public String get(IResource theResource) {
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), TITLE);
@ -344,6 +358,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* @see InstantDt
*/
public static final ResourceMetadataKeyEnum<InstantDt> UPDATED = new ResourceMetadataKeyEnum<InstantDt>("UPDATED") {
private static final long serialVersionUID = 1L;
@Override
public InstantDt get(IResource theResource) {
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), UPDATED);
@ -362,6 +377,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
* </p>
*/
public static final ResourceMetadataKeyEnum<String> VERSION = new ResourceMetadataKeyEnum<String>("VERSION") {
private static final long serialVersionUID = 1L;
@Override
public String get(IResource theResource) {
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION);
@ -383,6 +399,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
*/
@Deprecated
public static final ResourceMetadataKeyEnum<IdDt> VERSION_ID = new ResourceMetadataKeyEnum<IdDt>("VERSION_ID") {
private static final long serialVersionUID = 1L;
@Override
public IdDt get(IResource theResource) {
return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION_ID);
@ -519,26 +536,6 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
+ InstantDt.class.getCanonicalName());
}
private static StringDt getStringDtFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<StringDt> theKey) {
Object retValObj = theResourceMetadata.get(theKey);
if (retValObj == null) {
return null;
} else if (retValObj instanceof String) {
if (StringUtils.isBlank((String) retValObj)) {
return null;
}
return new StringDt((String) retValObj);
} else if (retValObj instanceof StringDt) {
if (((StringDt) retValObj).isEmpty()) {
return null;
} else {
return (StringDt) retValObj;
}
}
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
+ InstantDt.class.getCanonicalName());
}
private static String getStringFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<String> theKey) {
Object retValObj = theResourceMetadata.get(theKey);
if (retValObj == null) {

View File

@ -498,7 +498,11 @@ public abstract class BaseParser implements IParser {
List<IBase> entryResources = entryDef.getChildByName("resource").getAccessor().getValues(nextEntry);
if (entryResources != null && entryResources.size() > 0) {
IBaseResource res = (IBaseResource) entryResources.get(0);
String versionId = res.getIdElement().getVersionIdPart();
res.setId(value.getValueAsString());
if (isNotBlank(versionId) && res.getIdElement().hasVersionIdPart() == false) {
res.setId(res.getIdElement().withVersion(versionId));
}
}
}
}

View File

@ -100,6 +100,7 @@ import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
@ -940,6 +941,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return toResource(type.getImplementingClass(), theEntity);
}
@SuppressWarnings("unchecked")
protected <R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity) {
String resourceText = null;
switch (theEntity.getEncoding()) {
@ -975,7 +977,15 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
ourLog.error(msg, e);
throw new DataFormatException(msg, e);
}
IResource res = (IResource) retVal;
if (theEntity.getDeleted() != null) {
res = (IResource) myContext.getResourceDefinition(theResourceType).newInstance();
retVal = (R) res;
ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.DELETE);
}
res.setId(theEntity.getIdDt());
ResourceMetadataKeyEnum.VERSION.put(res, Long.toString(theEntity.getVersion()));
@ -986,10 +996,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
ResourceMetadataKeyEnum.TITLE.put(res, theEntity.getTitle());
}
if (theEntity.getDeleted() != null) {
ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
}
Collection<? extends BaseTag> tags = theEntity.getTags();
if (theEntity.isHasTags()) {
TagList tagList = new TagList();

View File

@ -397,8 +397,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return processMatchUrl(theMatchUrl, getResourceType());
}
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) {
@ -412,8 +411,7 @@ 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) {
@ -502,7 +500,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return new HashSet<Long>(q.getResultList());
}
private Set<Long> addPredicateUri(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
if (theList == null || theList.isEmpty()) {
return thePids;
@ -556,7 +553,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return new HashSet<Long>(q.getResultList());
}
private Set<Long> addPredicateParamMissing(Set<Long> thePids, String joinName, String theParamName, Class<? extends BaseResourceIndexedSearchParam> theParamTable) {
String resourceType = getContext().getResourceDefinition(getResourceType()).getName();
@ -1108,8 +1104,7 @@ 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;
@ -1128,8 +1123,7 @@ 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,8 +1137,7 @@ 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) {
@ -1164,12 +1157,10 @@ 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>());
@ -1332,8 +1323,7 @@ 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());
@ -1434,8 +1424,13 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
final T current = currentTmp;
String querySring = "SELECT count(h) FROM ResourceHistoryTable h " + "WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE" + " AND h.myUpdated < :END"
+ (theSince != null ? " AND h.myUpdated >= :SINCE" : "");
StringBuilder B = new StringBuilder();
B.append("SELECT count(h) FROM ResourceHistoryTable h ");
B.append("WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE");
B.append(" AND h.myUpdated < :END");
B.append((theSince != null ? " AND h.myUpdated >= :SINCE" : ""));
String querySring = B.toString();
TypedQuery<Long> countQuery = myEntityManager.createQuery(querySring, Long.class);
countQuery.setParameter("PID", translateForcedIdToPid(theId));
countQuery.setParameter("RESTYPE", resourceType);
@ -1473,8 +1468,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
retVal.add(current);
}
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery("SELECT h FROM ResourceHistoryTable h WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE AND h.myUpdated < :END "
+ (theSince != null ? " AND h.myUpdated >= :SINCE" : "") + " ORDER BY h.myUpdated ASC", ResourceHistoryTable.class);
StringBuilder b = new StringBuilder();
b.append("SELECT h FROM ResourceHistoryTable h WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE AND h.myUpdated < :END ");
b.append((theSince != null ? " AND h.myUpdated >= :SINCE" : ""));
b.append(" ORDER BY h.myUpdated DESC");
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery(b.toString(), ResourceHistoryTable.class);
q.setParameter("PID", translateForcedIdToPid(theId));
q.setParameter("RESTYPE", resourceType);
q.setParameter("END", end.getValue(), TemporalType.TIMESTAMP);
@ -1734,9 +1732,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
myEntityManager.merge(entity);
myEntityManager.flush();
ourLog.info("Processed metaDeleteOperation on {} in {}ms", new Object[] { theResourceId.getValue(), w.getMillisAndRestart() });
return metaGetOperation(theResourceId);
}
@ -1771,7 +1769,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
retVal.setLastUpdated(entity.getUpdated());
retVal.setVersionId(Long.toString(entity.getVersion()));
return retVal;
}
@ -1853,8 +1851,7 @@ 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()));
@ -2245,7 +2242,8 @@ 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;
@ -2373,8 +2371,7 @@ 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
@ -2409,8 +2406,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
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

@ -1,13 +1,12 @@
package ca.uhn.fhir.jpa.dao;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsInRelativeOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -22,9 +21,9 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@ -32,12 +31,10 @@ import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@ -45,10 +42,9 @@ import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
@ -62,15 +58,12 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Device;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Encounter;
import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Practitioner;
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.dstu2.valueset.QuantityComparatorEnum;
@ -85,17 +78,12 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.NumberParam;
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.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -110,26 +98,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2Test.class);
@Before
public void before() {
deleteAll(myPatientDao);
deleteAll(myObservationDao);
deleteAll(myOrganizationDao);
deleteAll(myDiagnosticReportDao);
deleteAll(myEncounterDao);
FhirSystemDaoDstu2Test.doDeleteEverything(mySystemDao);
reset(myInterceptor);
}
private void deleteAll(IFhirResourceDao<?> dao) {
IBundleProvider find = dao.search(new SearchParameterMap());
List<IBaseResource> res = find.getResources(0, find.size());
for (IBaseResource next : res) {
dao.delete(next.getIdElement());
}
}
private List<String> extractNames(IBundleProvider theSearch) {
ArrayList<String> retVal = new ArrayList<String>();
for (IBaseResource next : theSearch.getResources(0, theSearch.size())) {
@ -139,6 +107,46 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
return retVal;
}
@Test
public void testReadWithDeletedResource() {
String methodName = "testReadWithDeletedResource";
Patient patient = new Patient();
patient.addName().addFamily(methodName);
IIdType id = myPatientDao.create(patient).getId().toVersionless();
myPatientDao.delete(id);
try {
myPatientDao.read(id);
fail();
} catch (ResourceGoneException e) {
// good
}
patient.setId(id);
patient.addAddress().addLine("AAA");
myPatientDao.update(patient);
Patient p;
p = myPatientDao.read(id);
assertEquals(1, (p).getName().size());
p = myPatientDao.read(id.withVersion("1"));
assertEquals(1, (p).getName().size());
try {
myPatientDao.read(id.withVersion("2"));
fail();
} catch (ResourceGoneException e) {
// good
}
p = myPatientDao.read(id.withVersion("3"));
assertEquals(1, (p).getName().size());
}
@Test
public void testChoiceParamConcept() {
Observation o1 = new Observation();
@ -230,8 +238,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);
@ -709,6 +717,108 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertNotEquals(idv1, idv2);
}
@Test
public void testHistoryWithDeletedResource() throws Exception {
String methodName = "testHistoryWithDeletedResource";
Patient patient = new Patient();
patient.addName().addFamily(methodName);
IIdType id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
myPatientDao.delete(id);
patient.setId(id);
myPatientDao.update(patient);
IBundleProvider history = myPatientDao.history(id, null);
assertEquals(3, history.size());
List<IBaseResource> entries = history.getResources(0, 3);
ourLog.info("" + ResourceMetadataKeyEnum.UPDATED.get((IResource) entries.get(0)));
ourLog.info("" + ResourceMetadataKeyEnum.UPDATED.get((IResource) entries.get(1)));
ourLog.info("" + ResourceMetadataKeyEnum.UPDATED.get((IResource) entries.get(2)));
assertEquals(id.withVersion("3"), entries.get(0).getIdElement());
assertEquals(id.withVersion("2"), entries.get(1).getIdElement());
assertEquals(id.withVersion("1"), entries.get(2).getIdElement());
assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(0)));
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(1)));
assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(2)));
}
@Test
public void testHistoryOverMultiplePages() throws Exception {
String methodName = "testHistoryOverMultiplePages";
Patient patient = new Patient();
patient.addName().addFamily(methodName);
IIdType id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
Date middleDate = null;
for (int i = 0; i < 100; i++) {
if (i == 50) {
Thread.sleep(100);
middleDate = new Date();
Thread.sleep(100);
}
patient.setId(id);
patient.getName().get(0).getFamily().get(0).setValue(methodName + "_i");
myPatientDao.update(patient);
}
// By instance
IBundleProvider history = myPatientDao.history(id, null);
for (int i = 0; i < 100; i++) {
String expected = id.withVersion(Integer.toString(101 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
// By type
history = myPatientDao.history(null);
for (int i = 0; i < 100; i++) {
String expected = id.withVersion(Integer.toString(101 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
// By server
history = mySystemDao.history(null);
for (int i = 0; i < 100; i++) {
String expected = id.withVersion(Integer.toString(101 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
/*
* With since date
*/
// By instance
history = myPatientDao.history(id, middleDate);
for (int i = 0; i < 50; i++) {
String expected = id.withVersion(Integer.toString(101 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
// By type
history = myPatientDao.history(middleDate);
for (int i = 0; i < 50; i++) {
String expected = id.withVersion(Integer.toString(101 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
// By server
history = mySystemDao.history(middleDate);
for (int i = 0; i < 50; i++) {
String expected = id.withVersion(Integer.toString(101 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
}
@Test
public void testIdParam() {
Patient patient = new Patient();
@ -1130,21 +1240,21 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
id = myPatientDao.create(patient).getId();
}
assertTrue(id.hasVersionIdPart());
/*
* Create a second version
*/
Patient pt = myPatientDao.read(id);
pt.addName().addFamily("anotherName");
myPatientDao.update(pt);
/*
* Meta-Delete on previous version
*/
MetaDt meta = new MetaDt();
meta.addTag().setSystem("tag_scheme1").setCode("tag_code1");
meta.addProfile("http://profile/1");
@ -1156,11 +1266,11 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("tag_code2", newMeta.getTag().get(0).getCode());
assertEquals("http://profile/2", newMeta.getProfile().get(0).getValue());
assertEquals("seclabel_code2", newMeta.getSecurity().get(0).getCode());
/*
* Meta Read on Version
*/
meta = myPatientDao.metaGetOperation(id.withVersion("1"));
assertEquals(1, meta.getProfile().size());
assertEquals(1, meta.getSecurity().size());
@ -1168,7 +1278,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("tag_code2", meta.getTag().get(0).getCode());
assertEquals("http://profile/2", meta.getProfile().get(0).getValue());
assertEquals("seclabel_code2", meta.getSecurity().get(0).getCode());
/*
* Meta-read on Version 2
*/
@ -1189,7 +1299,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
/*
* Meta-Add on previous version
*/
meta = new MetaDt();
meta.addTag().setSystem("tag_scheme1").setCode("tag_code1");
meta.addProfile("http://profile/1");
@ -1198,11 +1308,11 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals(2, newMeta.getProfile().size());
assertEquals(2, newMeta.getSecurity().size());
assertEquals(2, newMeta.getTag().size());
/*
* Meta Read on Version
*/
meta = myPatientDao.metaGetOperation(id.withVersion("1"));
assertEquals(2, meta.getProfile().size());
assertEquals(2, meta.getSecurity().size());
@ -1228,7 +1338,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
/*
* Meta-Add on latest version
*/
meta = new MetaDt();
meta.addTag().setSystem("tag_scheme1").setCode("tag_code1");
meta.addProfile("http://profile/1");
@ -1238,7 +1348,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals(2, newMeta.getSecurity().size());
assertEquals(2, newMeta.getTag().size());
assertEquals("2", newMeta.getVersionId());
}
@Test
@ -1859,7 +1969,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
securityLabels.add(new CodingDt().setSystem("seclabel:sys:2").setCode("seclabel:code:2").setDisplay("seclabel:dis:2"));
ResourceMetadataKeyEnum.SECURITY_LABELS.put(patient, securityLabels);
ArrayList<IdDt> profiles = new ArrayList<IdDt>();
List<IdDt> profiles = new ArrayList<IdDt>();
profiles.add(new IdDt("http://profile/1"));
profiles.add(new IdDt("http://profile/2"));
ResourceMetadataKeyEnum.PROFILES.put(patient, profiles);
@ -1871,6 +1981,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
Patient retrieved = myPatientDao.read(patientId);
TagList published = (TagList) retrieved.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
sort(published);
assertEquals(2, published.size());
assertEquals("Dog", published.get(0).getTerm());
assertEquals("Puppies", published.get(0).getLabel());
@ -1878,14 +1989,18 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("Cat", published.get(1).getTerm());
assertEquals("Kittens", published.get(1).getLabel());
assertEquals("http://foo", published.get(1).getScheme());
assertEquals(2, ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).size());
assertEquals("seclabel:sys:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getSystemElement().getValue());
assertEquals("seclabel:code:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getCodeElement().getValue());
assertEquals("seclabel:dis:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getDisplayElement().getValue());
assertEquals("seclabel:sys:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getSystemElement().getValue());
assertEquals("seclabel:code:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getCodeElement().getValue());
assertEquals("seclabel:dis:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getDisplayElement().getValue());
assertEquals(2, ResourceMetadataKeyEnum.PROFILES.get(retrieved).size());
List<BaseCodingDt> secLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved);
sortCodings(secLabels);
assertEquals(2, secLabels.size());
assertEquals("seclabel:sys:1", secLabels.get(0).getSystemElement().getValue());
assertEquals("seclabel:code:1", secLabels.get(0).getCodeElement().getValue());
assertEquals("seclabel:dis:1", secLabels.get(0).getDisplayElement().getValue());
assertEquals("seclabel:sys:2", secLabels.get(1).getSystemElement().getValue());
assertEquals("seclabel:code:2", secLabels.get(1).getCodeElement().getValue());
assertEquals("seclabel:dis:2", secLabels.get(1).getDisplayElement().getValue());
profiles = ResourceMetadataKeyEnum.PROFILES.get(retrieved);
profiles = sortIds(profiles);
assertEquals(2, profiles.size());
assertEquals("http://profile/1", ResourceMetadataKeyEnum.PROFILES.get(retrieved).get(0).getValue());
assertEquals("http://profile/2", ResourceMetadataKeyEnum.PROFILES.get(retrieved).get(1).getValue());
@ -1899,13 +2014,13 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("Cat", published.get(1).getTerm());
assertEquals("Kittens", published.get(1).getLabel());
assertEquals("http://foo", published.get(1).getScheme());
assertEquals(2, ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).size());
assertEquals("seclabel:sys:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getSystemElement().getValue());
assertEquals("seclabel:code:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getCodeElement().getValue());
assertEquals("seclabel:dis:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getDisplayElement().getValue());
assertEquals("seclabel:sys:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getSystemElement().getValue());
assertEquals("seclabel:code:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getCodeElement().getValue());
assertEquals("seclabel:dis:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getDisplayElement().getValue());
assertEquals(2, secLabels.size());
assertEquals("seclabel:sys:1", secLabels.get(0).getSystemElement().getValue());
assertEquals("seclabel:code:1", secLabels.get(0).getCodeElement().getValue());
assertEquals("seclabel:dis:1", secLabels.get(0).getDisplayElement().getValue());
assertEquals("seclabel:sys:2", secLabels.get(1).getSystemElement().getValue());
assertEquals("seclabel:code:2", secLabels.get(1).getCodeElement().getValue());
assertEquals("seclabel:dis:2", secLabels.get(1).getDisplayElement().getValue());
assertEquals(2, ResourceMetadataKeyEnum.PROFILES.get(retrieved).size());
assertEquals("http://profile/1", ResourceMetadataKeyEnum.PROFILES.get(retrieved).get(0).getValue());
assertEquals("http://profile/2", ResourceMetadataKeyEnum.PROFILES.get(retrieved).get(1).getValue());
@ -1925,19 +2040,50 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("Cow", published.get(2).getTerm());
assertEquals("Calves", published.get(2).getLabel());
assertEquals("http://foo", published.get(2).getScheme());
assertEquals(2, ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).size());
assertEquals("seclabel:sys:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getSystemElement().getValue());
assertEquals("seclabel:code:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getCodeElement().getValue());
assertEquals("seclabel:dis:1", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(0).getDisplayElement().getValue());
assertEquals("seclabel:sys:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getSystemElement().getValue());
assertEquals("seclabel:code:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getCodeElement().getValue());
assertEquals("seclabel:dis:2", ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved).get(1).getDisplayElement().getValue());
assertEquals(2, secLabels.size());
assertEquals("seclabel:sys:1", secLabels.get(0).getSystemElement().getValue());
assertEquals("seclabel:code:1", secLabels.get(0).getCodeElement().getValue());
assertEquals("seclabel:dis:1", secLabels.get(0).getDisplayElement().getValue());
assertEquals("seclabel:sys:2", secLabels.get(1).getSystemElement().getValue());
assertEquals("seclabel:code:2", secLabels.get(1).getCodeElement().getValue());
assertEquals("seclabel:dis:2", secLabels.get(1).getDisplayElement().getValue());
assertEquals(2, ResourceMetadataKeyEnum.PROFILES.get(retrieved).size());
assertEquals("http://profile/1", ResourceMetadataKeyEnum.PROFILES.get(retrieved).get(0).getValue());
assertEquals("http://profile/2", ResourceMetadataKeyEnum.PROFILES.get(retrieved).get(1).getValue());
}
private List<IdDt> sortIds(List<IdDt> theProfiles) {
ArrayList<IdDt> retVal = new ArrayList<IdDt>(theProfiles);
Collections.sort(retVal, new Comparator<IdDt>() {
@Override
public int compare(IdDt theO1, IdDt theO2) {
return theO1.getValue().compareTo(theO2.getValue());
}});
return retVal;
}
private void sortCodings(List<BaseCodingDt> theSecLabels) {
Collections.sort(theSecLabels, new Comparator<BaseCodingDt>() {
@Override
public int compare(BaseCodingDt theO1, BaseCodingDt theO2) {
return theO1.getSystemElement().getValue().compareTo(theO2.getSystemElement().getValue());
}});
}
private void sort(TagList thePublished) {
ArrayList<Tag> tags = new ArrayList<Tag>(thePublished);
Collections.sort(tags, new Comparator<Tag>() {
@Override
public int compare(Tag theO1, Tag theO2) {
return defaultString(theO1.getScheme()).compareTo(defaultString(theO2.getScheme()));
}});
thePublished.clear();
for (Tag next : tags) {
thePublished.add(next);
}
}
@Test
public void testTokenParamWhichIsTooLong() {

View File

@ -101,6 +101,7 @@ import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
@ -424,7 +425,8 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
/*
* Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to make sure that works too..
* Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to
* make sure that works too..
*/
Socket sock = new Socket();
sock.setSoTimeout(3000);
@ -685,6 +687,30 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
}
@Test
public void testHistoryWithDeletedResource() {
String methodName = "testHistoryWithDeletedResource";
Patient patient = new Patient();
patient.addName().addFamily(methodName);
IIdType id = ourClient.create().resource(patient).execute().getId().toVersionless();
ourClient.delete().resourceById(id).execute();
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();
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());
assertEquals(id.withVersion("2"), history.getEntry().get(1).getResource().getId());
assertEquals(HTTPVerbEnum.DELETE, history.getEntry().get(1).getRequest().getMethodElement().getValueAsEnum());
assertEquals(0, ((Patient) history.getEntry().get(1).getResource()).getName().size());
assertEquals(id.withVersion("1"), history.getEntry().get(2).getResource().getId());
assertEquals(1, ((Patient) history.getEntry().get(2).getResource()).getName().size());
}
/**
* See issue #52
*/
@ -703,6 +729,21 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
@Test
public void testMetadata() throws Exception {
HttpGet get = new HttpGet(ourServerBase + "/metadata");
CloseableHttpResponse response = ourHttpClient.execute(get);
try {
String resp = IOUtils.toString(response.getEntity().getContent());
ourLog.info(resp);
assertEquals(200, response.getStatusLine().getStatusCode());
assertThat(resp, stringContainsInOrder("THIS IS THE DESC"));
} finally {
IOUtils.closeQuietly(response.getEntity().getContent());
response.close();
}
}
@Test
public void testMetaOperations() throws Exception {
String methodName = "testMetaOperations";
@ -838,7 +879,7 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals(1, actual.getEntry().size());
assertEquals(ourServerBase + "/Patient/" + p1Id.getIdPart(), actual.getEntry().get(0).getFullUrl());
assertEquals(p1Id.getIdPart(), actual.getEntry().get(0).getResource().getId().getIdPart());
@ -853,8 +894,7 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01");
IdDt p1Id = (IdDt) ourClient.create().resource(p1).execute().getId();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint()
.execute();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint().execute();
assertEquals(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());
@ -989,6 +1029,19 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
}
private void testSearchReturnsResults(String search) throws IOException, ClientProtocolException {
int matches;
HttpGet get = new HttpGet(ourServerBase + search);
CloseableHttpResponse response = ourHttpClient.execute(get);
String resp = IOUtils.toString(response.getEntity().getContent());
IOUtils.closeQuietly(response.getEntity().getContent());
ourLog.info(resp);
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, resp);
matches = bundle.getTotal();
assertThat(matches, greaterThan(0));
}
@Test
public void testSearchReturnsSearchDate() throws Exception {
Date before = new Date();
@ -1047,33 +1100,6 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
assertEquals(BundleEntrySearchModeEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
}
@Test
public void testSearchWithTextInexactMatch() throws Exception {
Observation obs = new Observation();
obs.getCode().setText("THIS_IS_THE_TEXT");
obs.getCode().addCoding().setSystem("SYSTEM").setCode("CODE").setDisplay("THIS_IS_THE_DISPLAY");
ourClient.create().resource(obs).execute();
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_TEXT");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_");
testSearchReturnsResults("/Observation?code%3Atext=this_is_the_");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_DISPLAY");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_disp");
}
private void testSearchReturnsResults(String search) throws IOException, ClientProtocolException {
int matches;
HttpGet get = new HttpGet(ourServerBase + search);
CloseableHttpResponse response = ourHttpClient.execute(get);
String resp = IOUtils.toString(response.getEntity().getContent());
IOUtils.closeQuietly(response.getEntity().getContent());
ourLog.info(resp);
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, resp);
matches = bundle.getTotal();
assertThat(matches, greaterThan(0));
}
@Test
public void testSearchWithMissing() throws Exception {
ourLog.info("Starting testSearchWithMissing");
@ -1153,6 +1179,20 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
checkParamMissing(Observation.SP_DATE);
}
@Test
public void testSearchWithTextInexactMatch() throws Exception {
Observation obs = new Observation();
obs.getCode().setText("THIS_IS_THE_TEXT");
obs.getCode().addCoding().setSystem("SYSTEM").setCode("CODE").setDisplay("THIS_IS_THE_DISPLAY");
ourClient.create().resource(obs).execute();
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_TEXT");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_");
testSearchReturnsResults("/Observation?code%3Atext=this_is_the_");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_DISPLAY");
testSearchReturnsResults("/Observation?code%3Atext=THIS_IS_THE_disp");
}
/**
* See #198
*/
@ -1281,7 +1321,7 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
//@formatter:om
}
/**
* Test for issue #60
*/
@ -1637,21 +1677,6 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
ourHttpClient.close();
}
@Test
public void testMetadata() throws Exception {
HttpGet get = new HttpGet(ourServerBase + "/metadata");
CloseableHttpResponse response = ourHttpClient.execute(get);
try {
String resp = IOUtils.toString(response.getEntity().getContent());
ourLog.info(resp);
assertEquals(200, response.getStatusLine().getStatusCode());
assertThat(resp, stringContainsInOrder("THIS IS THE DESC"));
} finally {
IOUtils.closeQuietly(response.getEntity().getContent());
response.close();
}
}
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() throws Exception {

View File

@ -51,6 +51,7 @@ import ca.uhn.fhir.model.dstu2.valueset.SearchEntryModeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
import ca.uhn.fhir.rest.server.BundleInclusionRule;
@ -147,6 +148,10 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
if (next.getId().hasBaseUrl()) {
entry.setFullUrl(next.getId().getValue());
}
BundleEntryTransactionMethodEnum httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
if (httpVerb != null) {
entry.getRequest().getMethodElement().setValueAsString(httpVerb.getCode());
}
}
/*
@ -238,6 +243,10 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
} while (references.isEmpty() == false);
Entry entry = myBundle.addEntry().setResource(next);
BundleEntryTransactionMethodEnum httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
if (httpVerb != null) {
entry.getRequest().getMethodElement().setValueAsString(httpVerb.getCode());
}
populateBundleEntryFullUrl(next, entry);
BundleEntrySearchModeEnum searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(next);

View File

@ -92,6 +92,21 @@ public class XmlParserDstu2Test {
private static final FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class);
@Test
public void testParseBundleWithResourceId() {
//@formatter:off
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">"
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"3\"/><lastUpdated value=\"2015-09-11T23:35:43.273-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"2\"/><lastUpdated value=\"2015-09-11T23:35:42.849-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"1\"/><lastUpdated value=\"2015-09-11T23:35:42.295-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
+ "</Bundle>\n";
//@formatter:on
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, input);
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/3", bundle.getEntry().get(0).getResource().getId().getValue());
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/2", bundle.getEntry().get(1).getResource().getId().getValue());
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/1", bundle.getEntry().get(2).getResource().getId().getValue());
}
@Test
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {

View File

@ -182,6 +182,10 @@
RestfulServer now supports dynamically adding and removing resource providers
at runtime. Thanks to Bill Denton for adding this.
</action>
<action type="add">
JPA server now correctly suppresses contents of deleted resources
in history
</action>
</release>
<release version="1.1" date="2015-07-13">
<action type="add">