Performance enhancements on the CapabilityStatement generator for JPA
server
This commit is contained in:
parent
e299b062a6
commit
593a705365
|
@ -619,12 +619,14 @@ public class IdDt extends UriDt implements /*IPrimitiveDatatype<String>, */IIdTy
|
|||
/**
|
||||
* Creates a new instance of this ID which is identical, but refers to the specific version of this resource ID noted by theVersion.
|
||||
*
|
||||
* @param theVersion The actual version string, e.g. "1"
|
||||
* @param theVersion The actual version string, e.g. "1". If theVersion is blank or null, returns the same as {@link #toVersionless()}}
|
||||
* @return A new instance of IdDt which is identical, but refers to the specific version of this resource ID noted by theVersion.
|
||||
*/
|
||||
@Override
|
||||
public IdDt withVersion(String theVersion) {
|
||||
Validate.notBlank(theVersion, "Version may not be null or empty");
|
||||
if (isBlank(theVersion)) {
|
||||
return toVersionless();
|
||||
}
|
||||
|
||||
if (isLocal() || isUrn()) {
|
||||
return new IdDt(getValueAsString());
|
||||
|
|
|
@ -4,8 +4,10 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu2;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.instance.hapi.validation.ValidationSupportChain;
|
||||
|
@ -17,6 +19,8 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -113,6 +117,13 @@ public class BaseDstu2Config extends BaseConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "myResourceCountsCache")
|
||||
public SingleItemLoadingCache<Map<String, Long>> resourceCountsCache() {
|
||||
SingleItemLoadingCache<Map<String, Long>> retVal = new SingleItemLoadingCache<>(() -> systemDaoDstu2().getResourceCounts());
|
||||
retVal.setCacheMillis(60 * DateUtils.MILLIS_PER_SECOND);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologySvc terminologyService() {
|
||||
return new HapiTerminologySvcDstu2();
|
||||
|
|
|
@ -14,8 +14,10 @@ import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu3;
|
|||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcDstu3;
|
||||
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
|
@ -26,6 +28,8 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -77,6 +81,14 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Bean(name = "myResourceCountsCache")
|
||||
public SingleItemLoadingCache<Map<String, Long>> resourceCountsCache() {
|
||||
SingleItemLoadingCache<Map<String, Long>> retVal = new SingleItemLoadingCache<>(() -> systemDaoDstu3().getResourceCounts());
|
||||
retVal.setCacheMillis(60 * DateUtils.MILLIS_PER_SECOND);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IFulltextSearchSvc searchDaoDstu3() {
|
||||
FulltextSearchSvcImpl searchDao = new FulltextSearchSvcImpl();
|
||||
|
|
|
@ -15,8 +15,10 @@ import ca.uhn.fhir.jpa.term.HapiTerminologySvcR4;
|
|||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
|
||||
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.rest.server.GraphQLProvider;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
|
@ -29,6 +31,8 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -92,6 +96,13 @@ public class BaseR4Config extends BaseConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "myResourceCountsCache")
|
||||
public SingleItemLoadingCache<Map<String, Long>> resourceCountsCache() {
|
||||
SingleItemLoadingCache<Map<String, Long>> retVal = new SingleItemLoadingCache<>(() -> systemDaoR4().getResourceCounts());
|
||||
retVal.setCacheMillis(60 * DateUtils.MILLIS_PER_SECOND);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IFulltextSearchSvc searchDaoR4() {
|
||||
FulltextSearchSvcImpl searchDao = new FulltextSearchSvcImpl();
|
||||
|
|
|
@ -31,6 +31,7 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
|||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||
import ca.uhn.fhir.jpa.util.ExpungeOptions;
|
||||
import ca.uhn.fhir.jpa.util.ExpungeOutcome;
|
||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
||||
|
@ -79,9 +80,12 @@ import org.springframework.data.domain.Slice;
|
|||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
|
@ -717,14 +721,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return mySearchParamExtractor.extractSearchParamUri(theEntity, theResource);
|
||||
}
|
||||
|
||||
private void extractTagsHapi(IResource theResource, ResourceTable theEntity, Set<TagDefinition> allDefs) {
|
||||
private void extractTagsHapi(IResource theResource, ResourceTable theEntity, Set<ResourceTag> allDefs) {
|
||||
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource);
|
||||
if (tagList != null) {
|
||||
for (Tag next : tagList) {
|
||||
TagDefinition tag = getTagOrNull(TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel());
|
||||
if (tag != null) {
|
||||
TagDefinition def = getTagOrNull(TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel());
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
allDefs.add(tag);
|
||||
theEntity.addTag(tag);
|
||||
theEntity.setHasTags(true);
|
||||
}
|
||||
}
|
||||
|
@ -733,10 +737,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
List<BaseCodingDt> securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(theResource);
|
||||
if (securityLabels != null) {
|
||||
for (BaseCodingDt next : securityLabels) {
|
||||
TagDefinition tag = getTagOrNull(TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue());
|
||||
if (tag != null) {
|
||||
TagDefinition def = getTagOrNull(TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue());
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
allDefs.add(tag);
|
||||
theEntity.addTag(tag);
|
||||
theEntity.setHasTags(true);
|
||||
}
|
||||
}
|
||||
|
@ -745,24 +749,24 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
List<IdDt> profiles = ResourceMetadataKeyEnum.PROFILES.get(theResource);
|
||||
if (profiles != null) {
|
||||
for (IIdType next : profiles) {
|
||||
TagDefinition tag = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
|
||||
if (tag != null) {
|
||||
TagDefinition def = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
allDefs.add(tag);
|
||||
theEntity.addTag(tag);
|
||||
theEntity.setHasTags(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractTagsRi(IAnyResource theResource, ResourceTable theEntity, Set<TagDefinition> allDefs) {
|
||||
private void extractTagsRi(IAnyResource theResource, ResourceTable theEntity, Set<ResourceTag> theAllTags) {
|
||||
List<? extends IBaseCoding> tagList = theResource.getMeta().getTag();
|
||||
if (tagList != null) {
|
||||
for (IBaseCoding next : tagList) {
|
||||
TagDefinition tag = getTagOrNull(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay());
|
||||
if (tag != null) {
|
||||
allDefs.add(tag);
|
||||
theEntity.addTag(tag);
|
||||
TagDefinition def = getTagOrNull(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay());
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
theEntity.setHasTags(true);
|
||||
}
|
||||
}
|
||||
|
@ -771,10 +775,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
List<? extends IBaseCoding> securityLabels = theResource.getMeta().getSecurity();
|
||||
if (securityLabels != null) {
|
||||
for (IBaseCoding next : securityLabels) {
|
||||
TagDefinition tag = getTagOrNull(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay());
|
||||
if (tag != null) {
|
||||
allDefs.add(tag);
|
||||
theEntity.addTag(tag);
|
||||
TagDefinition def = getTagOrNull(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay());
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
theEntity.setHasTags(true);
|
||||
}
|
||||
}
|
||||
|
@ -783,10 +787,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
List<? extends IPrimitiveType<String>> profiles = theResource.getMeta().getProfile();
|
||||
if (profiles != null) {
|
||||
for (IPrimitiveType<String> next : profiles) {
|
||||
TagDefinition tag = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
|
||||
if (tag != null) {
|
||||
allDefs.add(tag);
|
||||
theEntity.addTag(tag);
|
||||
TagDefinition def = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(def);
|
||||
theAllTags.add(tag);
|
||||
theEntity.setHasTags(true);
|
||||
}
|
||||
}
|
||||
|
@ -876,10 +880,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
ourLog.debug("Session flush took {}ms for {} inserts and {} updates", sw.getMillis(), insertionCount, updateCount);
|
||||
}
|
||||
|
||||
private Set<TagDefinition> getAllTagDefinitions(ResourceTable theEntity) {
|
||||
HashSet<TagDefinition> retVal = Sets.newHashSet();
|
||||
for (ResourceTag next : theEntity.getTags()) {
|
||||
retVal.add(next.getTag());
|
||||
private Set<ResourceTag> getAllTagDefinitions(ResourceTable theEntity) {
|
||||
HashSet<ResourceTag> retVal = Sets.newHashSet();
|
||||
if (theEntity.isHasTags()) {
|
||||
for (ResourceTag next : theEntity.getTags()) {
|
||||
retVal.add(next);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
@ -1173,7 +1179,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
/**
|
||||
* Returns true if the resource has changed (either the contents or the tags)
|
||||
*/
|
||||
protected EncodedResource populateResourceIntoEntity(IBaseResource theResource, ResourceTable theEntity, boolean theUpdateHash) {
|
||||
protected EncodedResource populateResourceIntoEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, boolean theUpdateHash) {
|
||||
if (theEntity.getResourceType() == null) {
|
||||
theEntity.setResourceType(toResourceName(theResource));
|
||||
}
|
||||
|
@ -1222,11 +1228,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
theEntity.setHashSha256(hashSha256);
|
||||
}
|
||||
|
||||
Set<TagDefinition> allDefs = new HashSet<>();
|
||||
|
||||
theEntity.setHasTags(false);
|
||||
|
||||
Set<TagDefinition> allTagsOld = getAllTagDefinitions(theEntity);
|
||||
Set<ResourceTag> allDefs = new HashSet<>();
|
||||
Set<ResourceTag> allTagsOld = getAllTagDefinitions(theEntity);
|
||||
|
||||
if (theResource instanceof IResource) {
|
||||
extractTagsHapi((IResource) theResource, theEntity, allDefs);
|
||||
|
@ -1238,32 +1241,33 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
if (def.isStandardType() == false) {
|
||||
String profile = def.getResourceProfile("");
|
||||
if (isNotBlank(profile)) {
|
||||
TagDefinition tag = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null);
|
||||
if (tag != null) {
|
||||
TagDefinition profileDef = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null);
|
||||
if (def != null) {
|
||||
ResourceTag tag = theEntity.addTag(profileDef);
|
||||
allDefs.add(tag);
|
||||
theEntity.addTag(tag);
|
||||
theEntity.setHasTags(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<ResourceTag> existingTags = new ArrayList<>();
|
||||
if (theEntity.isHasTags()) {
|
||||
existingTags.addAll(theEntity.getTags());
|
||||
}
|
||||
for (ResourceTag next : existingTags) {
|
||||
TagDefinition nextDef = next.getTag();
|
||||
if (!allDefs.contains(nextDef)) {
|
||||
if (shouldDroppedTagBeRemovedOnUpdate(theEntity, next)) {
|
||||
// Don't keep duplicate tags
|
||||
Set<TagDefinition> allDefsPresent = new HashSet<>();
|
||||
theEntity.getTags().removeIf(theResourceTag -> !allDefsPresent.add(theResourceTag.getTag()));
|
||||
|
||||
// Remove any tags that have been removed
|
||||
for (ResourceTag next : allTagsOld) {
|
||||
if (!allDefs.contains(next)) {
|
||||
if (shouldDroppedTagBeRemovedOnUpdate(theRequest, next)) {
|
||||
theEntity.getTags().remove(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<TagDefinition> allTagsNew = getAllTagDefinitions(theEntity);
|
||||
Set<ResourceTag> allTagsNew = getAllTagDefinitions(theEntity);
|
||||
if (!allTagsOld.equals(allTagsNew)) {
|
||||
changed = true;
|
||||
}
|
||||
theEntity.setHasTags(!allTagsNew.isEmpty());
|
||||
|
||||
} else {
|
||||
theEntity.setHashSha256(null);
|
||||
|
@ -1486,17 +1490,47 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* The default implementation removes any profile declarations, but leaves tags and security labels in place. Subclasses may choose to override and change this behaviour.
|
||||
* </p>
|
||||
* <p>
|
||||
* See <a href="http://hl7.org/fhir/2015Sep/resource.html#1.11.3.7">Updates to Tags, Profiles, and Security Labels</a> for a description of the logic that the default behaviour folows.
|
||||
* See <a href="http://hl7.org/fhir/resource.html#tag-updates">Updates to Tags, Profiles, and Security Labels</a> for a description of the logic that the default behaviour folows.
|
||||
* </p>
|
||||
*
|
||||
* @param theEntity The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||
* @param theTag The tag
|
||||
* @param theTag The tag
|
||||
* @return Returns <code>true</code> if the tag should be removed
|
||||
*/
|
||||
protected boolean shouldDroppedTagBeRemovedOnUpdate(ResourceTable theEntity, ResourceTag theTag) {
|
||||
if (theTag.getTag().getTagType() == TagTypeEnum.PROFILE) {
|
||||
protected boolean shouldDroppedTagBeRemovedOnUpdate(RequestDetails theRequest, ResourceTag theTag) {
|
||||
|
||||
Set<TagTypeEnum> metaSnapshotModeTokens = null;
|
||||
|
||||
if (theRequest != null) {
|
||||
List<String> metaSnapshotMode = theRequest.getHeaders(JpaConstants.HEADER_META_SNAPSHOT_MODE);
|
||||
if (metaSnapshotMode != null && !metaSnapshotMode.isEmpty()) {
|
||||
metaSnapshotModeTokens = new HashSet<>();
|
||||
for (String nextHeaderValue : metaSnapshotMode) {
|
||||
StringTokenizer tok = new StringTokenizer(nextHeaderValue, ",");
|
||||
while (tok.hasMoreTokens()) {
|
||||
switch (trim(tok.nextToken())) {
|
||||
case "TAG":
|
||||
metaSnapshotModeTokens.add(TagTypeEnum.TAG);
|
||||
break;
|
||||
case "PROFILE":
|
||||
metaSnapshotModeTokens.add(TagTypeEnum.PROFILE);
|
||||
break;
|
||||
case "SECURITY_LABEL":
|
||||
metaSnapshotModeTokens.add(TagTypeEnum.SECURITY_LABEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (metaSnapshotModeTokens == null) {
|
||||
metaSnapshotModeTokens = Collections.singleton(TagTypeEnum.PROFILE);
|
||||
}
|
||||
|
||||
if (metaSnapshotModeTokens.contains(theTag.getTag().getTagType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1514,7 +1548,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation) {
|
||||
public <R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity,
|
||||
boolean theForHistoryOperation) {
|
||||
|
||||
ResourceHistoryTable history;
|
||||
if (theEntity instanceof ResourceHistoryTable) {
|
||||
|
@ -1639,7 +1674,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ResourceTable updateEntity(final IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, final IBaseResource theResource, ResourceTable
|
||||
theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ourLog.debug("Starting entity update");
|
||||
|
||||
|
@ -1732,7 +1768,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
theEntity.setNarrativeTextParsedIntoWords(null);
|
||||
theEntity.setContentTextParsedIntoWords(null);
|
||||
theEntity.setHashSha256(null);
|
||||
changed = populateResourceIntoEntity(theResource, theEntity, true);
|
||||
changed = populateResourceIntoEntity(theRequest, theResource, theEntity, true);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -1844,7 +1880,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
*/
|
||||
compositeStringUniques = extractCompositeStringUniques(theEntity, stringParams, tokenParams, numberParams, quantityParams, dateParams, uriParams, links);
|
||||
|
||||
changed = populateResourceIntoEntity(theResource, theEntity, true);
|
||||
changed = populateResourceIntoEntity(theRequest, theResource, theEntity, true);
|
||||
|
||||
theEntity.setUpdated(theUpdateTime);
|
||||
if (theResource instanceof IResource) {
|
||||
|
@ -1874,7 +1910,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
|
||||
} else {
|
||||
|
||||
changed = populateResourceIntoEntity(theResource, theEntity, false);
|
||||
changed = populateResourceIntoEntity(theRequest, theResource, theEntity, false);
|
||||
|
||||
theEntity.setUpdated(theUpdateTime);
|
||||
// theEntity.setLanguage(theResource.getLanguage().getValue());
|
||||
|
@ -2062,11 +2098,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return theEntity;
|
||||
}
|
||||
|
||||
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable entity, Date theDeletedTimestampOrNull, Date theUpdateTime) {
|
||||
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime, false, true);
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable
|
||||
entity, Date theDeletedTimestampOrNull, Date theUpdateTime) {
|
||||
return updateEntity(theRequest, theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime, false, true);
|
||||
}
|
||||
|
||||
public ResourceTable updateInternal(T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion, RequestDetails theRequestDetails, ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) {
|
||||
public ResourceTable updateInternal(RequestDetails theRequest, T theResource, boolean thePerformIndexing,
|
||||
boolean theForceUpdateVersion, RequestDetails theRequestDetails, ResourceTable theEntity, IIdType
|
||||
theResourceId, IBaseResource theOldResource) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = null;
|
||||
if (theRequestDetails != null) {
|
||||
|
@ -2085,7 +2124,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
// Perform update
|
||||
ResourceTable savedEntity = updateEntity(theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
||||
ResourceTable savedEntity = updateEntity(theRequest, theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
||||
|
||||
/*
|
||||
* If we aren't indexing (meaning we're probably executing a sub-operation within a transaction),
|
||||
|
@ -2271,14 +2310,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* @param theResourceType E.g. <code>Patient
|
||||
* @param thePartsChoices E.g. <code>[[gender=male], [name=SMITH, name=JOHN]]</code>
|
||||
*/
|
||||
public static Set<String> extractCompositeStringUniquesValueChains(String theResourceType, List<List<String>> thePartsChoices) {
|
||||
public static Set<String> extractCompositeStringUniquesValueChains(String
|
||||
theResourceType, List<List<String>> thePartsChoices) {
|
||||
|
||||
for (List<String> next : thePartsChoices) {
|
||||
for (Iterator<String> iter = next.iterator(); iter.hasNext(); ) {
|
||||
if (isBlank(iter.next())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
next.removeIf(StringUtils::isBlank);
|
||||
if (next.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
@ -2288,19 +2324,16 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Collections.sort(thePartsChoices, new Comparator<List<String>>() {
|
||||
@Override
|
||||
public int compare(List<String> o1, List<String> o2) {
|
||||
String str1 = null;
|
||||
String str2 = null;
|
||||
if (o1.size() > 0) {
|
||||
str1 = o1.get(0);
|
||||
}
|
||||
if (o2.size() > 0) {
|
||||
str2 = o2.get(0);
|
||||
}
|
||||
return StringUtils.compare(str1, str2);
|
||||
thePartsChoices.sort((o1, o2) -> {
|
||||
String str1 = null;
|
||||
String str2 = null;
|
||||
if (o1.size() > 0) {
|
||||
str1 = o1.get(0);
|
||||
}
|
||||
if (o2.size() > 0) {
|
||||
str2 = o2.get(0);
|
||||
}
|
||||
return compare(str1, str2);
|
||||
});
|
||||
|
||||
List<String> values = new ArrayList<>();
|
||||
|
@ -2309,7 +2342,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return queryStringsToPopulate;
|
||||
}
|
||||
|
||||
private static void extractCompositeStringUniquesValueChains(String theResourceType, List<List<String>> thePartsChoices, List<String> theValues, Set<String> theQueryStringsToPopulate) {
|
||||
private static void extractCompositeStringUniquesValueChains(String
|
||||
theResourceType, List<List<String>> thePartsChoices, List<String> theValues, Set<String> theQueryStringsToPopulate) {
|
||||
if (thePartsChoices.size() > 0) {
|
||||
List<String> nextList = thePartsChoices.get(0);
|
||||
Collections.sort(nextList);
|
||||
|
@ -2446,14 +2480,15 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
private static List<BaseCodingDt> toBaseCodingList(List<IBaseCoding> theSecurityLabels) {
|
||||
ArrayList<BaseCodingDt> retVal = new ArrayList<BaseCodingDt>(theSecurityLabels.size());
|
||||
ArrayList<BaseCodingDt> retVal = new ArrayList<>(theSecurityLabels.size());
|
||||
for (IBaseCoding next : theSecurityLabels) {
|
||||
retVal.add((BaseCodingDt) next);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected static Long translateForcedIdToPid(String theResourceName, String theResourceId, IForcedIdDao theForcedIdDao) {
|
||||
protected static Long translateForcedIdToPid(String theResourceName, String theResourceId, IForcedIdDao
|
||||
theForcedIdDao) {
|
||||
return translateForcedIdToPids(new IdDt(theResourceName, theResourceId), theForcedIdDao).get(0);
|
||||
}
|
||||
|
||||
|
@ -2482,7 +2517,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
public static SearchParameterMap translateMatchUrl(IDao theCallingDao, FhirContext theContext, String theMatchUrl, RuntimeResourceDefinition resourceDef) {
|
||||
public static SearchParameterMap translateMatchUrl(IDao theCallingDao, FhirContext theContext, String
|
||||
theMatchUrl, RuntimeResourceDefinition resourceDef) {
|
||||
SearchParameterMap paramMap = new SearchParameterMap();
|
||||
List<NameValuePair> parameters = translateMatchUrl(theMatchUrl);
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
||||
import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.*;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
@ -175,7 +176,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome delete(IIdType theId, List<DeleteConflict> theDeleteConflicts, RequestDetails theRequestDetails) {
|
||||
public DaoMethodOutcome delete(IIdType theId, List<DeleteConflict> theDeleteConflicts, RequestDetails theReques) {
|
||||
if (theId == null || !theId.hasIdPart()) {
|
||||
throw new InvalidRequestException("Can not perform delete, no ID provided");
|
||||
}
|
||||
|
@ -208,12 +209,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
T resourceToDelete = toResource(myResourceType, entity, false);
|
||||
|
||||
// Notify IServerOperationInterceptors about pre-action call
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
||||
if (theReques != null) {
|
||||
theReques.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourcePreDelete(theRequestDetails, resourceToDelete);
|
||||
((IServerOperationInterceptor) next).resourcePreDelete(theReques, resourceToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,23 +223,23 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
preDelete(resourceToDelete, entity);
|
||||
|
||||
// Notify interceptors
|
||||
if (theRequestDetails != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theId.getResourceType(), theId);
|
||||
if (theReques != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theReques, getContext(), theId.getResourceType(), theId);
|
||||
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
|
||||
}
|
||||
|
||||
Date updateTime = new Date();
|
||||
ResourceTable savedEntity = updateEntity(null, entity, updateTime, updateTime);
|
||||
ResourceTable savedEntity = updateEntity(theReques, null, entity, updateTime, updateTime);
|
||||
resourceToDelete.setId(entity.getIdDt());
|
||||
|
||||
// Notify JPA interceptors
|
||||
if (theRequestDetails != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theId.getResourceType(), theId);
|
||||
theRequestDetails.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
||||
if (theReques != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theReques, getContext(), theId.getResourceType(), theId);
|
||||
theReques.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceDeleted(theRequestDetails, resourceToDelete);
|
||||
((IServerOperationInterceptor) next).resourceDeleted(theReques, resourceToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,7 +273,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
* transaction processors
|
||||
*/
|
||||
@Override
|
||||
public DeleteMethodOutcome deleteByUrl(String theUrl, List<DeleteConflict> deleteConflicts, RequestDetails theRequestDetails) {
|
||||
public DeleteMethodOutcome deleteByUrl(String theUrl, List<DeleteConflict> deleteConflicts, RequestDetails theRequest) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
Set<Long> resource = processMatchUrl(theUrl, myResourceType);
|
||||
|
@ -290,12 +291,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
T resourceToDelete = toResource(myResourceType, entity, false);
|
||||
|
||||
// Notify IServerOperationInterceptors about pre-action call
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
||||
if (theRequest != null) {
|
||||
theRequest.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourcePreDelete(theRequestDetails, resourceToDelete);
|
||||
((IServerOperationInterceptor) next).resourcePreDelete(theRequest, resourceToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,24 +304,24 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
// Notify interceptors
|
||||
IdDt idToDelete = entity.getIdDt();
|
||||
if (theRequestDetails != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, idToDelete.getResourceType(), idToDelete);
|
||||
if (theRequest != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, idToDelete.getResourceType(), idToDelete);
|
||||
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
|
||||
}
|
||||
|
||||
// Perform delete
|
||||
Date updateTime = new Date();
|
||||
updateEntity(null, entity, updateTime, updateTime);
|
||||
updateEntity(theRequest, null, entity, updateTime, updateTime);
|
||||
resourceToDelete.setId(entity.getIdDt());
|
||||
|
||||
// Notify JPA interceptors
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, idToDelete.getResourceType(), idToDelete);
|
||||
if (theRequest != null) {
|
||||
theRequest.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, idToDelete.getResourceType(), idToDelete);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceDeleted(theRequestDetails, resourceToDelete);
|
||||
((IServerOperationInterceptor) next).resourceDeleted(theRequest, resourceToDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +367,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
}
|
||||
|
||||
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing, Date theUpdateTime, RequestDetails theRequestDetails) {
|
||||
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing, Date theUpdateTime, RequestDetails theRequest) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
preProcessResourceForStorage(theResource);
|
||||
|
@ -405,23 +406,23 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
// Notify interceptors
|
||||
if (theRequestDetails != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theResource);
|
||||
if (theRequest != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getContext(), theResource);
|
||||
notifyInterceptors(RestOperationTypeEnum.CREATE, requestDetails);
|
||||
}
|
||||
|
||||
// Notify JPA interceptors
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourcePreCreate(theResource);
|
||||
if (theRequest != null) {
|
||||
theRequest.getRequestOperationCallback().resourcePreCreate(theResource);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourcePreCreate(theRequestDetails, theResource);
|
||||
((IServerOperationInterceptor) next).resourcePreCreate(theRequest, theResource);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform actual DB update
|
||||
ResourceTable updatedEntity = updateEntity(theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
||||
ResourceTable updatedEntity = updateEntity(theRequest, theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
||||
theResource.setId(entity.getIdDt());
|
||||
|
||||
|
||||
|
@ -436,12 +437,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
// Notify JPA interceptors
|
||||
if (!updatedEntity.isUnchangedInCurrentOperation()) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourceCreated(theResource);
|
||||
if (theRequest != null) {
|
||||
theRequest.getRequestOperationCallback().resourceCreated(theResource);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceCreated(theRequestDetails, theResource);
|
||||
((IServerOperationInterceptor) next).resourceCreated(theRequest, theResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -931,7 +932,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
public void reindex(T theResource, ResourceTable theEntity) {
|
||||
ourLog.debug("Indexing resource {} - PID {}", theResource.getIdElement().getValue(), theEntity.getId());
|
||||
CURRENTLY_REINDEXING.put(theResource, Boolean.TRUE);
|
||||
updateEntity(theResource, theEntity, null, true, false, theEntity.getUpdatedDate(), true, false);
|
||||
updateEntity(null, theResource, theEntity, null, true, false, theEntity.getUpdatedDate(), true, false);
|
||||
CURRENTLY_REINDEXING.put(theResource, null);
|
||||
}
|
||||
|
||||
|
@ -1232,7 +1233,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
/*
|
||||
* If we aren't indexing, that means we're doing this inside a transaction.
|
||||
* The transaction will do the actual storate to the database a bit later on,
|
||||
* The transaction will do the actual storage to the database a bit later on,
|
||||
* after placeholder IDs have been replaced, by calling {@link #updateInternal}
|
||||
* directly. So we just bail now.
|
||||
*/
|
||||
|
@ -1245,7 +1246,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
/*
|
||||
* Otherwise, we're not in a transaction
|
||||
*/
|
||||
ResourceTable savedEntity = updateInternal(theResource, thePerformIndexing, theForceUpdateVersion, theRequestDetails, entity, resourceId, oldResource);
|
||||
ResourceTable savedEntity = updateInternal(theRequestDetails, theResource, thePerformIndexing, theForceUpdateVersion, theRequestDetails, entity, resourceId, oldResource);
|
||||
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, theResource).setCreated(false);
|
||||
|
||||
if (!thePerformIndexing) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
|||
import ca.uhn.fhir.jpa.util.ExpungeOptions;
|
||||
import ca.uhn.fhir.jpa.util.ExpungeOutcome;
|
||||
import ca.uhn.fhir.jpa.util.ReindexFailureException;
|
||||
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
|
@ -15,6 +16,7 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
|
@ -23,16 +25,10 @@ import org.springframework.transaction.support.TransactionCallback;
|
|||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
@ -74,6 +70,10 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
|
|||
private PlatformTransactionManager myTxManager;
|
||||
@Autowired
|
||||
private IResourceTableDao myResourceTableDao;
|
||||
@Autowired
|
||||
@Qualifier("myResourceCountsCache")
|
||||
public SingleItemLoadingCache<Map<String, Long>> myResourceCountsCache;
|
||||
|
||||
|
||||
private int doPerformReindexingPass(final Integer theCount) {
|
||||
/*
|
||||
|
@ -165,23 +165,23 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
|
|||
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
|
||||
@Override
|
||||
public Map<String, Long> getResourceCounts() {
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
||||
Root<?> from = cq.from(ResourceTable.class);
|
||||
cq.multiselect(from.get("myResourceType").as(String.class), builder.count(from.get("myResourceType")).as(Long.class));
|
||||
cq.groupBy(from.get("myResourceType"));
|
||||
|
||||
TypedQuery<Tuple> q = myEntityManager.createQuery(cq);
|
||||
|
||||
Map<String, Long> retVal = new HashMap<>();
|
||||
for (Tuple next : q.getResultList()) {
|
||||
String resourceName = next.get(0, String.class);
|
||||
Long count = next.get(1, Long.class);
|
||||
retVal.put(resourceName, count);
|
||||
|
||||
List<Map<?,?>> counts = myResourceTableDao.getResourceCounts();
|
||||
for (Map<?, ?> next : counts) {
|
||||
retVal.put(next.get("type").toString(), Long.parseLong(next.get("count").toString()));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, Long> getResourceCountsFromCache() {
|
||||
return myResourceCountsCache.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider history(Date theSince, Date theUntil, RequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
|||
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -39,8 +40,6 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
|
||||
public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subscription> implements IFhirResourceDaoSubscription<Subscription> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSubscriptionDstu2.class);
|
||||
|
||||
@Autowired
|
||||
private ISubscriptionTableDao mySubscriptionTableDao;
|
||||
|
||||
|
@ -74,9 +73,9 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
|||
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
if (theDeletedTimestampOrNull != null) {
|
||||
mySubscriptionTableDao.deleteAllForSubscription(theEntity);
|
||||
|
|
|
@ -387,9 +387,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
|
||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
updateInternal(theRequestDetails, nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, updateTime, false, true);
|
||||
updateEntity(theRequestDetails, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, updateTime, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ import ca.uhn.fhir.jpa.util.ExpungeOutcome;
|
|||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -41,6 +44,14 @@ public interface IFhirSystemDao<T, MT> extends IDao {
|
|||
|
||||
Map<String, Long> getResourceCounts();
|
||||
|
||||
/**
|
||||
*Returns a cached count of resources using a cache that regularly
|
||||
* refreshes in the background. This method will never
|
||||
*/
|
||||
@Nullable
|
||||
Map<String, Long> getResourceCountsFromCache();
|
||||
|
||||
|
||||
IBundleProvider history(Date theDate, Date theUntil, RequestDetails theRequestDetails);
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,9 @@ import org.springframework.data.jpa.repository.Modifying;
|
|||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -42,6 +45,9 @@ public interface IResourceTableDao extends JpaRepository<ResourceTable, Long> {
|
|||
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myIndexStatus IS NULL")
|
||||
Slice<Long> findUnindexed(Pageable thePageRequest);
|
||||
|
||||
@Query("SELECT t.myResourceType as type, COUNT(*) as count FROM ResourceTable t GROUP BY t.myResourceType")
|
||||
List<Map<?,?>> getResourceCounts();
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE ResourceTable r SET r.myIndexStatus = null WHERE r.myResourceType = :restype")
|
||||
int markResourcesOfTypeAsRequiringReindexing(@Param("restype") String theResourceType);
|
||||
|
|
|
@ -199,9 +199,9 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
CodeSystem cs = (CodeSystem) theResource;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
|||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
|
@ -82,9 +83,9 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
|
|||
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
if (theDeletedTimestampOrNull != null) {
|
||||
mySubscriptionTableDao.deleteAllForSubscription(theEntity);
|
||||
|
|
|
@ -545,9 +545,9 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
|
||||
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
updateInternal(theRequestDetails, nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||
updateEntity(theRequestDetails, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.hl7.fhir.r4.model.Coding;
|
|||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -172,9 +173,9 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
CodeSystem cs = (CodeSystem) theResource;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
|||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -36,7 +37,6 @@ import org.hl7.fhir.r4.model.Subscription;
|
|||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
|
@ -75,9 +75,9 @@ public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscriptio
|
|||
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
if (theDeletedTimestampOrNull != null) {
|
||||
Long subscriptionId = getSubscriptionTablePidForSubscriptionResource(theEntity.getIdDt());
|
||||
|
|
|
@ -51,7 +51,6 @@ import ca.uhn.fhir.util.FhirTerser;
|
|||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil.UrlParts;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import javolution.io.Struct;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
@ -317,7 +316,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date theUpdateTime, Set<IdType> theAllIds,
|
||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(RequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date theUpdateTime, Set<IdType> theAllIds,
|
||||
Map<IdType, IdType> theIdSubstitutions, Map<IdType, DaoMethodOutcome> theIdToPersistedOutcome, Bundle theResponse, IdentityHashMap<BundleEntryComponent, Integer> theOriginalRequestOrder, List<BundleEntryComponent> theEntries) {
|
||||
Set<String> deletedResources = new HashSet<>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||
|
@ -545,9 +544,9 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
|
||||
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
updateInternal(theRequestDetails, nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||
updateEntity(theRequestDetails, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -713,7 +712,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
}
|
||||
|
||||
private static void handleTransactionCreateOrUpdateOutcome(Map<IdType, IdType> idSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, IdType nextResourceId, DaoMethodOutcome outcome,
|
||||
BundleEntryComponent newEntry, String theResourceType, IBaseResource theRes, ServletRequestDetails theRequestDetails) {
|
||||
BundleEntryComponent newEntry, String theResourceType, IBaseResource theRes, RequestDetails theRequestDetails) {
|
||||
IdType newId = (IdType) outcome.getId().toUnqualifiedVersionless();
|
||||
IdType resourceId = isPlaceholder(nextResourceId) ? nextResourceId : nextResourceId.toUnqualifiedVersionless();
|
||||
if (newId.equals(resourceId) == false) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
||||
|
@ -44,6 +45,8 @@ import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider;
|
|||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
|
||||
public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
|
||||
|
||||
private volatile Conformance myCachedValue;
|
||||
|
@ -52,16 +55,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
|
|||
private boolean myIncludeResourceCounts;
|
||||
private RestfulServer myRestfulServer;
|
||||
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@CoverageIgnore
|
||||
public JpaConformanceProviderDstu2(){
|
||||
super();
|
||||
super.setCache(false);
|
||||
setIncludeResourceCounts(true);
|
||||
}
|
||||
private SingleItemLoadingCache<Map<String, Long>> myResourceCountsCache;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -79,10 +73,11 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
|
|||
public Conformance getServerConformance(HttpServletRequest theRequest) {
|
||||
Conformance retVal = myCachedValue;
|
||||
|
||||
Map<String, Long> counts = Collections.emptyMap();
|
||||
Map<String, Long> counts = null;
|
||||
if (myIncludeResourceCounts) {
|
||||
counts = mySystemDao.getResourceCounts();
|
||||
counts = mySystemDao.getResourceCountsFromCache();
|
||||
}
|
||||
counts = defaultIfNull(counts, Collections.emptyMap());
|
||||
|
||||
FhirContext ctx = myRestfulServer.getFhirContext();
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ import ca.uhn.fhir.jpa.util.JpaConstants;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||
import ca.uhn.fhir.model.primitive.BooleanDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
|
@ -79,35 +81,33 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
|
|||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_NAME_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = org.hl7.fhir.r4.model.IntegerType.class)
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerDt.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@IdParam IIdType theIdParam,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) org.hl7.fhir.r4.model.IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) org.hl7.fhir.r4.model.BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) org.hl7.fhir.r4.model.BooleanType theExpungeOldVersions
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerDt theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanDt theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanDt theExpungeOldVersions
|
||||
) {
|
||||
org.hl7.fhir.r4.model.Parameters retVal = super.doExpunge(theIdParam, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null);
|
||||
return JpaSystemProviderDstu2.toExpungeResponse(retVal);
|
||||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_NAME_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = org.hl7.fhir.r4.model.IntegerType.class)
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerDt.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) org.hl7.fhir.r4.model.IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) org.hl7.fhir.r4.model.BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) org.hl7.fhir.r4.model.BooleanType theExpungeOldVersions
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerDt theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanDt theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanDt theExpungeOldVersions
|
||||
) {
|
||||
org.hl7.fhir.r4.model.Parameters retVal = super.doExpunge(null, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null);
|
||||
return JpaSystemProviderDstu2.toExpungeResponse(retVal);
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name = OPERATION_NAME_META, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = MetaDt.class)
|
||||
})
|
||||
//@formatter:on
|
||||
public Parameters meta(RequestDetails theRequestDetails) {
|
||||
Parameters parameters = new Parameters();
|
||||
MetaDt metaGetOperation = getDao().metaGetOperation(MetaDt.class, theRequestDetails);
|
||||
|
@ -115,11 +115,9 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
|
|||
return parameters;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name = OPERATION_NAME_META, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = MetaDt.class)
|
||||
})
|
||||
//@formatter:on
|
||||
public Parameters meta(@IdParam IdDt theId, RequestDetails theRequestDetails) {
|
||||
Parameters parameters = new Parameters();
|
||||
MetaDt metaGetOperation = getDao().metaGetOperation(MetaDt.class, theId, theRequestDetails);
|
||||
|
|
|
@ -187,8 +187,8 @@ public class JpaSystemProviderDstu2 extends BaseJpaSystemProviderDstu2Plus<Bundl
|
|||
public Parameters getResourceCounts() {
|
||||
Parameters retVal = new Parameters();
|
||||
|
||||
Map<String, Long> counts = mySystemDao.getResourceCounts();
|
||||
counts = new TreeMap<String, Long>(counts);
|
||||
Map<String, Long> counts = mySystemDao.getResourceCountsFromCache();
|
||||
counts = new TreeMap<>(counts);
|
||||
for (Entry<String, Long> nextEntry : counts.entrySet()) {
|
||||
retVal.addParameter().setName(new StringDt(nextEntry.getKey())).setValue(new IntegerDt(nextEntry.getValue().intValue()));
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ import ca.uhn.fhir.rest.server.RestfulServer;
|
|||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
|
||||
public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider {
|
||||
|
||||
private volatile CapabilityStatement myCachedValue;
|
||||
|
@ -70,10 +72,11 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se
|
|||
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
|
||||
CapabilityStatement retVal = myCachedValue;
|
||||
|
||||
Map<String, Long> counts = Collections.emptyMap();
|
||||
Map<String, Long> counts = null;
|
||||
if (myIncludeResourceCounts) {
|
||||
counts = mySystemDao.getResourceCounts();
|
||||
counts = mySystemDao.getResourceCountsFromCache();
|
||||
}
|
||||
counts = defaultIfNull(counts, Collections.emptyMap());
|
||||
|
||||
retVal = super.getServerConformance(theRequest);
|
||||
for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
|
||||
|
|
|
@ -31,9 +31,7 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_30_40;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Meta;
|
||||
import org.hl7.fhir.dstu3.model.Parameters;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -83,13 +81,13 @@ public class JpaResourceProviderDstu3<T extends IAnyResource> extends BaseJpaRes
|
|||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_NAME_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = org.hl7.fhir.r4.model.IntegerType.class)
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@IdParam IIdType theIdParam,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) org.hl7.fhir.r4.model.IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) org.hl7.fhir.r4.model.BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) org.hl7.fhir.r4.model.BooleanType theExpungeOldVersions
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions
|
||||
) {
|
||||
org.hl7.fhir.r4.model.Parameters retVal = super.doExpunge(theIdParam, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null);
|
||||
try {
|
||||
|
@ -100,12 +98,12 @@ public class JpaResourceProviderDstu3<T extends IAnyResource> extends BaseJpaRes
|
|||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_NAME_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = org.hl7.fhir.r4.model.IntegerType.class)
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) org.hl7.fhir.r4.model.IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) org.hl7.fhir.r4.model.BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) org.hl7.fhir.r4.model.BooleanType theExpungeOldVersions
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions
|
||||
) {
|
||||
org.hl7.fhir.r4.model.Parameters retVal = super.doExpunge(null, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null);
|
||||
try {
|
||||
|
@ -139,11 +137,9 @@ public class JpaResourceProviderDstu3<T extends IAnyResource> extends BaseJpaRes
|
|||
return parameters;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name = OPERATION_NAME_META_ADD, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = Meta.class)
|
||||
})
|
||||
//@formatter:on
|
||||
public Parameters metaAdd(@IdParam IdType theId, @OperationParam(name = "meta") Meta theMeta, RequestDetails theRequestDetails) {
|
||||
if (theMeta == null) {
|
||||
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
|
||||
|
@ -154,11 +150,9 @@ public class JpaResourceProviderDstu3<T extends IAnyResource> extends BaseJpaRes
|
|||
return parameters;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name = OPERATION_NAME_META_DELETE, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = Meta.class)
|
||||
})
|
||||
//@formatter:on
|
||||
public Parameters metaDelete(@IdParam IdType theId, @OperationParam(name = "meta") Meta theMeta, RequestDetails theRequestDetails) {
|
||||
if (theMeta == null) {
|
||||
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
|
||||
|
|
|
@ -191,8 +191,8 @@ public class JpaSystemProviderDstu3 extends BaseJpaSystemProviderDstu2Plus<Bundl
|
|||
public Parameters getResourceCounts() {
|
||||
Parameters retVal = new Parameters();
|
||||
|
||||
Map<String, Long> counts = mySystemDao.getResourceCounts();
|
||||
counts = new TreeMap<String, Long>(counts);
|
||||
Map<String, Long> counts = mySystemDao.getResourceCountsFromCache();
|
||||
counts = new TreeMap<>(counts);
|
||||
for (Entry<String, Long> nextEntry : counts.entrySet()) {
|
||||
retVal.addParameter().setName((nextEntry.getKey())).setValue(new IntegerType(nextEntry.getValue().intValue()));
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ import ca.uhn.fhir.rest.server.RestfulServer;
|
|||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
|
||||
public class JpaConformanceProviderR4 extends org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider {
|
||||
|
||||
private volatile CapabilityStatement myCachedValue;
|
||||
|
@ -70,10 +72,11 @@ public class JpaConformanceProviderR4 extends org.hl7.fhir.r4.hapi.rest.server.S
|
|||
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
|
||||
CapabilityStatement retVal = myCachedValue;
|
||||
|
||||
Map<String, Long> counts = Collections.emptyMap();
|
||||
Map<String, Long> counts = null;
|
||||
if (myIncludeResourceCounts) {
|
||||
counts = mySystemDao.getResourceCounts();
|
||||
counts = mySystemDao.getResourceCountsFromCache();
|
||||
}
|
||||
counts = defaultIfNull(counts, Collections.emptyMap());
|
||||
|
||||
retVal = super.getServerConformance(theRequest);
|
||||
for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
|
||||
|
|
|
@ -177,8 +177,8 @@ public class JpaSystemProviderR4 extends BaseJpaSystemProviderDstu2Plus<Bundle,
|
|||
public Parameters getResourceCounts() {
|
||||
Parameters retVal = new Parameters();
|
||||
|
||||
Map<String, Long> counts = mySystemDao.getResourceCounts();
|
||||
counts = new TreeMap<String, Long>(counts);
|
||||
Map<String, Long> counts = mySystemDao.getResourceCountsFromCache();
|
||||
counts = new TreeMap<>(counts);
|
||||
for (Entry<String, Long> nextEntry : counts.entrySet()) {
|
||||
retVal.addParameter().setName((nextEntry.getKey())).setValue(new IntegerType(nextEntry.getValue().intValue()));
|
||||
}
|
||||
|
|
|
@ -92,4 +92,11 @@ public class JpaConstants {
|
|||
* Output parameter name for the $expunge operation
|
||||
*/
|
||||
public static final String OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT = "count";
|
||||
/**
|
||||
* Header name for the "X-Meta-Snapshot-Mode" header, which
|
||||
* specifies that properties in meta (tags, profiles, security labels)
|
||||
* should be treated as a snapshot, meaning that these things will
|
||||
* be removed if they are nt explicitly included in updates
|
||||
*/
|
||||
public static final String HEADER_META_SNAPSHOT_MODE = "X-Meta-Snapshot-Mode";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* Smile CDR - CDR
|
||||
* %%
|
||||
* Copyright (C) 2016 - 2018 Simpatico Intelligent Systems Inc
|
||||
* %%
|
||||
* All rights reserved.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* This is a simple cache for CapabilityStatement resources to
|
||||
* be returned as server metadata.
|
||||
*/
|
||||
public class SingleItemLoadingCache<T> {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SingleItemLoadingCache.class);
|
||||
private static Long ourNowForUnitTest;
|
||||
private final Callable<T> myFetcher;
|
||||
private volatile long myCacheMillis;
|
||||
private AtomicReference<T> myCapabilityStatement = new AtomicReference<>();
|
||||
private long myLastFetched;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SingleItemLoadingCache(Callable<T> theFetcher) {
|
||||
myFetcher = theFetcher;
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
ourLog.info("Clearning cache");
|
||||
myCapabilityStatement.set(null);
|
||||
myLastFetched = 0;
|
||||
}
|
||||
|
||||
public synchronized T get() {
|
||||
return myCapabilityStatement.get();
|
||||
}
|
||||
|
||||
private T refresh() {
|
||||
T retVal;
|
||||
try {
|
||||
retVal = myFetcher.call();
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
myCapabilityStatement.set(retVal);
|
||||
myLastFetched = now();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public void setCacheMillis(long theCacheMillis) {
|
||||
myCacheMillis = theCacheMillis;
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 60000)
|
||||
public void update() {
|
||||
if (myCacheMillis > 0) {
|
||||
long now = now();
|
||||
long expiry = now - myCacheMillis;
|
||||
if (myLastFetched < expiry) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long now() {
|
||||
if (ourNowForUnitTest != null) {
|
||||
return ourNowForUnitTest;
|
||||
}
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void setNowForUnitTest(Long theNowForUnitTest) {
|
||||
ourNowForUnitTest = theNowForUnitTest;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2018 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
|
||||
/**
|
||||
* Utility to get the Spring proxy object's target object
|
||||
*/
|
||||
public class SpringObjectCaster {
|
||||
|
||||
/**
|
||||
* Retrieve the Spring proxy object's target object
|
||||
* @param proxy
|
||||
* @param clazz
|
||||
* @param <T>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T> T getTargetObject(Object proxy, Class<T> clazz) throws Exception {
|
||||
while( (AopUtils.isJdkDynamicProxy(proxy))) {
|
||||
return clazz.cast(getTargetObject(((Advised)proxy).getTargetSource().getTarget(), clazz));
|
||||
}
|
||||
|
||||
return clazz.cast(proxy);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class FhirResourceDaoR4UpdateTagSnapshotTest extends BaseJpaR4Test {
|
||||
|
||||
@Test
|
||||
public void testUpdateWithDuplicateTagsWithHeader() {
|
||||
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(Lists.newArrayList("TAG"));
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.getMeta().addTag("urn:foo", "bar2", "baz");
|
||||
p.getMeta().addTag("urn:foo", "bar2", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = myPatientDao.read(new IdType("A"), mySrd);
|
||||
assertEquals(2, p.getMeta().getTag().size());
|
||||
|
||||
p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = myPatientDao.read(new IdType("A"), mySrd);
|
||||
// It would be nice if this didn't trigger a version update but
|
||||
// i guess it's not so bad that it does
|
||||
assertEquals("2", p.getIdElement().getVersionIdPart());
|
||||
assertEquals(true, p.getActive());
|
||||
assertEquals(1, p.getMeta().getTag().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithFewerTagsNoHeader() {
|
||||
Patient p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.getMeta().addTag("urn:foo", "bar2", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = myPatientDao.read(new IdType("A"), mySrd);
|
||||
assertEquals("1", p.getIdElement().getVersionIdPart());
|
||||
assertEquals(true, p.getActive());
|
||||
assertEquals(2, p.getMeta().getTag().size());
|
||||
assertEquals("urn:foo", p.getMeta().getTag().get(0).getSystem());
|
||||
assertThat(p.getMeta().getTag().get(0).getCode(), Matchers.anyOf(Matchers.equalTo("bar"), Matchers.equalTo("bar2")));
|
||||
}
|
||||
@Test
|
||||
public void testUpdateWithFewerTagsWithHeader() {
|
||||
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(Lists.newArrayList("TAG"));
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.getMeta().addTag("urn:foo", "bar2", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = myPatientDao.read(new IdType("A"), mySrd);
|
||||
// It would be nice if this didn't trigger a version update but
|
||||
// i guess it's not so bad that it does
|
||||
assertEquals("2", p.getIdElement().getVersionIdPart());
|
||||
assertEquals(true, p.getActive());
|
||||
assertEquals(1, p.getMeta().getTag().size());
|
||||
assertEquals("urn:foo", p.getMeta().getTag().get(0).getSystem());
|
||||
assertEquals("bar", p.getMeta().getTag().get(0).getCode());
|
||||
assertEquals("baz", p.getMeta().getTag().get(0).getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoTagsNoHeader() {
|
||||
Patient p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = new Patient();
|
||||
p.setId("A");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = myPatientDao.read(new IdType("A"), mySrd);
|
||||
assertEquals("1", p.getIdElement().getVersionIdPart());
|
||||
assertEquals(true, p.getActive());
|
||||
assertEquals(1, p.getMeta().getTag().size());
|
||||
assertEquals("urn:foo", p.getMeta().getTag().get(0).getSystem());
|
||||
assertEquals("bar", p.getMeta().getTag().get(0).getCode());
|
||||
assertEquals("baz", p.getMeta().getTag().get(0).getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoTagsWithHeader() {
|
||||
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(Lists.newArrayList("TAG"));
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("A");
|
||||
p.getMeta().addTag("urn:foo", "bar", "baz");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = new Patient();
|
||||
p.setId("A");
|
||||
p.setActive(true);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
p = myPatientDao.read(new IdType("A"), mySrd);
|
||||
assertEquals(true, p.getActive());
|
||||
assertEquals(0, p.getMeta().getTag().size());
|
||||
// It would be nice if this didn't trigger a version update but
|
||||
// i guess it's not so bad that it does
|
||||
assertEquals("2", p.getIdElement().getVersionIdPart());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -37,6 +37,7 @@ import java.math.BigDecimal;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
@ -169,6 +170,24 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceCounts() {
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
myPatientDao.create(p);
|
||||
|
||||
Observation o = new Observation();
|
||||
o.setStatus(ObservationStatus.AMENDED);
|
||||
myObservationDao.create(o);
|
||||
|
||||
Map<String, Long> counts = mySystemDao.getResourceCounts();
|
||||
assertEquals(new Long(1L), counts.get("Patient"));
|
||||
assertEquals(new Long(1L), counts.get("Observation"));
|
||||
assertEquals(null, counts.get("Organization"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBatchCreateWithBadRead() {
|
||||
Bundle request = new Bundle();
|
||||
|
|
|
@ -7,6 +7,7 @@ import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
|||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
||||
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
|
@ -40,6 +41,7 @@ import org.springframework.web.servlet.DispatcherServlet;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -61,6 +63,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
private TerminologyUploaderProviderR4 myTerminologyUploaderProvider;
|
||||
private Object ourGraphQLProvider;
|
||||
private boolean ourRestHookSubscriptionInterceptorRequested;
|
||||
protected SingleItemLoadingCache<Map<String, Long>> ourResourceCountsCache;
|
||||
|
||||
public BaseResourceProviderR4Test() {
|
||||
super();
|
||||
|
@ -99,6 +102,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
ourRestServer.setServerConformanceProvider(confProvider);
|
||||
|
||||
ourPagingProvider = myAppCtx.getBean(DatabaseBackedPagingProvider.class);
|
||||
ourResourceCountsCache = (SingleItemLoadingCache<Map<String, Long>>) myAppCtx.getBean("myResourceCountsCache");
|
||||
|
||||
Server server = new Server(ourPort);
|
||||
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ServerR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerR4Test.class);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* See #519
|
||||
*/
|
||||
|
@ -55,11 +56,64 @@ public class ServerR4Test extends BaseResourceProviderR4Test {
|
|||
}
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMetadataIncludesResourceCounts() {
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
myClient.create().resource(p).execute();
|
||||
|
||||
/*
|
||||
* Initial fetch after a clear should return
|
||||
* no results
|
||||
*/
|
||||
ourResourceCountsCache.clear();
|
||||
|
||||
CapabilityStatement capabilityStatement = myClient
|
||||
.capabilities()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
|
||||
Extension patientCountExt = capabilityStatement
|
||||
.getRest()
|
||||
.get(0)
|
||||
.getResource()
|
||||
.stream()
|
||||
.filter(t -> t.getType().equals("Patient"))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new InternalErrorException("No patient"))
|
||||
.getExtensionByUrl(ExtensionConstants.CONF_RESOURCE_COUNT);
|
||||
assertNull(patientCountExt);
|
||||
|
||||
/*
|
||||
* Now run a background pass (the update
|
||||
* method is called by the scheduler normally)
|
||||
*/
|
||||
ourResourceCountsCache.update();
|
||||
|
||||
capabilityStatement = myClient
|
||||
.capabilities()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
|
||||
patientCountExt = capabilityStatement
|
||||
.getRest()
|
||||
.get(0)
|
||||
.getResource()
|
||||
.stream()
|
||||
.filter(t -> t.getType().equals("Patient"))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new InternalErrorException("No patient"))
|
||||
.getExtensionByUrl(ExtensionConstants.CONF_RESOURCE_COUNT);
|
||||
assertEquals("1", patientCountExt.getValueAsPrimitive().getValueAsString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SingleItemLoadingCacheTest {
|
||||
|
||||
@Mock
|
||||
private Callable<CapabilityStatement> myFetcher;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
SingleItemLoadingCache.setNowForUnitTest(null);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
AtomicInteger id = new AtomicInteger();
|
||||
when(myFetcher.call()).thenAnswer(t->{
|
||||
CapabilityStatement retVal = new CapabilityStatement();
|
||||
retVal.setId("" + id.incrementAndGet());
|
||||
return retVal;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCache() {
|
||||
long start = System.currentTimeMillis();
|
||||
SingleItemLoadingCache.setNowForUnitTest(start);
|
||||
|
||||
// Cache is initialized on startup
|
||||
SingleItemLoadingCache<CapabilityStatement> cache = new SingleItemLoadingCache<>(myFetcher);
|
||||
cache.setCacheMillis(500);
|
||||
assertEquals(null, cache.get());
|
||||
|
||||
// Not time to update yet
|
||||
cache.update();
|
||||
assertEquals("1", cache.get().getId());
|
||||
|
||||
// Wait a bit, still not time to update
|
||||
SingleItemLoadingCache.setNowForUnitTest(start + 400);
|
||||
cache.update();
|
||||
assertEquals("1", cache.get().getId());
|
||||
|
||||
// Wait a bit more and the cache is expired
|
||||
SingleItemLoadingCache.setNowForUnitTest(start + 800);
|
||||
cache.update();
|
||||
assertEquals("2", cache.get().getId());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -257,7 +257,11 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
|
||||
@Override
|
||||
public IBaseMetaType setLastUpdated(Date theHeaderDateValue) {
|
||||
ResourceMetadataKeyEnum.UPDATED.put(BaseResource.this, new InstantDt(theHeaderDateValue));
|
||||
if (theHeaderDateValue == null) {
|
||||
getResourceMetadata().remove(ResourceMetadataKeyEnum.UPDATED);
|
||||
} else {
|
||||
ResourceMetadataKeyEnum.UPDATED.put(BaseResource.this, new InstantDt(theHeaderDateValue));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -669,14 +669,15 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
|
|||
* Creates a new instance of this ID which is identical, but refers to the
|
||||
* specific version of this resource ID noted by theVersion.
|
||||
*
|
||||
* @param theVersion
|
||||
* The actual version string, e.g. "1"
|
||||
* @param theVersion The actual version string, e.g. "1". If theVersion is blank or null, returns the same as {@link #toVersionless()}}
|
||||
* @return A new instance of IdType which is identical, but refers to the
|
||||
* specific version of this resource ID noted by theVersion.
|
||||
*/
|
||||
@Override
|
||||
public IdType withVersion(String theVersion) {
|
||||
Validate.notBlank(theVersion, "Version may not be null or empty");
|
||||
if (isBlank(theVersion)) {
|
||||
return toVersionless();
|
||||
}
|
||||
|
||||
if (isLocal() || isUrn()) {
|
||||
return new IdType(getValueAsString());
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
package ca.uhn.fhir.model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Reference;
|
||||
|
@ -14,82 +9,19 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class IdTypeDstu3Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IdTypeDstu3Test.class);
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IdTypeDstu3Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUuid() {
|
||||
IdType id = new IdType("urn:uuid:1234-5678");
|
||||
assertEquals("urn:uuid:1234-5678", id.getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.getIdPart());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("urn:uuid:1234-5678", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOid() {
|
||||
IdType id = new IdType("urn:oid:1.2.3.4");
|
||||
assertEquals("urn:oid:1.2.3.4", id.getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.getIdPart());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("urn:oid:1.2.3.4", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocal() {
|
||||
IdType id = new IdType("#foo");
|
||||
assertEquals("#foo", id.getValueAsString());
|
||||
assertEquals("#foo", id.getIdPart());
|
||||
assertEquals("#foo", id.toUnqualified().getValueAsString());
|
||||
assertEquals("#foo", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("#foo", id.withResourceType("Patient").getValue());
|
||||
assertEquals("#foo", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("#foo", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormal() {
|
||||
IdType id = new IdType("foo");
|
||||
assertEquals("foo", id.getValueAsString());
|
||||
assertEquals("foo", id.getIdPart());
|
||||
assertEquals("foo", id.toUnqualified().getValueAsString());
|
||||
assertEquals("foo", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("Patient/foo", id.withResourceType("Patient").getValue());
|
||||
assertEquals("http://foo/Patient/foo", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("foo/_history/2", id.withVersion("2").getValue());
|
||||
private Patient parseAndEncode(Patient patient) {
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
ourLog.info("\n" + encoded);
|
||||
return ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -125,44 +57,13 @@ public class IdTypeDstu3Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocal() {
|
||||
IdType id;
|
||||
public void testBigDecimalIds() {
|
||||
|
||||
id = new IdType("#123");
|
||||
assertEquals("#123", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
IdType id = new IdType(new BigDecimal("123"));
|
||||
assertEquals(id.getIdPartAsBigDecimal(), new BigDecimal("123"));
|
||||
|
||||
id = new IdType("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1");
|
||||
assertEquals("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("http://example.com/Patient/33#123");
|
||||
assertEquals("http://example.com/Patient/33#123", id.getValue());
|
||||
assertFalse(id.isLocal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorsWithNullArguments() {
|
||||
IdType id = new IdType(null, null, null);
|
||||
assertEquals(null, id.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocalBase() {
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #67
|
||||
*/
|
||||
|
@ -187,6 +88,44 @@ public class IdTypeDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorsWithNullArguments() {
|
||||
IdType id = new IdType(null, null, null);
|
||||
assertEquals(null, id.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocal() {
|
||||
IdType id;
|
||||
|
||||
id = new IdType("#123");
|
||||
assertEquals("#123", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1");
|
||||
assertEquals("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("http://example.com/Patient/33#123");
|
||||
assertEquals("http://example.com/Patient/33#123", id.getValue());
|
||||
assertFalse(id.isLocal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocalBase() {
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetermineBase() {
|
||||
|
||||
|
@ -203,6 +142,54 @@ public class IdTypeDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocal() {
|
||||
IdType id = new IdType("#foo");
|
||||
assertEquals("#foo", id.getValueAsString());
|
||||
assertEquals("#foo", id.getIdPart());
|
||||
assertEquals("#foo", id.toUnqualified().getValueAsString());
|
||||
assertEquals("#foo", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("#foo", id.withResourceType("Patient").getValue());
|
||||
assertEquals("#foo", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("#foo", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormal() {
|
||||
IdType id = new IdType("foo");
|
||||
assertEquals("foo", id.getValueAsString());
|
||||
assertEquals("foo", id.getIdPart());
|
||||
assertEquals("foo", id.toUnqualified().getValueAsString());
|
||||
assertEquals("foo", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("Patient/foo", id.withResourceType("Patient").getValue());
|
||||
assertEquals("http://foo/Patient/foo", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("foo/_history/2", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOid() {
|
||||
IdType id = new IdType("urn:oid:1.2.3.4");
|
||||
assertEquals("urn:oid:1.2.3.4", id.getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.getIdPart());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("urn:oid:1.2.3.4", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueAbsolute() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -218,14 +205,6 @@ public class IdTypeDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigDecimalIds() {
|
||||
|
||||
IdType id = new IdType(new BigDecimal("123"));
|
||||
assertEquals(id.getIdPartAsBigDecimal(), new BigDecimal("123"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueAbsoluteWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -241,30 +220,6 @@ public class IdTypeDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testViewMethods() {
|
||||
IdType i = new IdType("http://foo/fhir/Organization/123/_history/999");
|
||||
assertEquals("Organization/123/_history/999", i.toUnqualified().getValue());
|
||||
assertEquals("http://foo/fhir/Organization/123", i.toVersionless().getValue());
|
||||
assertEquals("Organization/123", i.toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("/123/_history/999");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals(null, ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
assertEquals(null, ref.getReferenceElement().getVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueMissingType1() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -321,10 +276,53 @@ public class IdTypeDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
private Patient parseAndEncode(Patient patient) {
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
ourLog.info("\n" + encoded);
|
||||
return ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
||||
@Test
|
||||
public void testParseValueWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("/123/_history/999");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals(null, ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
assertEquals(null, ref.getReferenceElement().getVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUuid() {
|
||||
IdType id = new IdType("urn:uuid:1234-5678");
|
||||
assertEquals("urn:uuid:1234-5678", id.getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.getIdPart());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("urn:uuid:1234-5678", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testViewMethods() {
|
||||
IdType i = new IdType("http://foo/fhir/Organization/123/_history/999");
|
||||
assertEquals("Organization/123/_history/999", i.toUnqualified().getValue());
|
||||
assertEquals("http://foo/fhir/Organization/123", i.toVersionless().getValue());
|
||||
assertEquals("Organization/123", i.toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithVersionNull() {
|
||||
assertEquals("Patient/123", new IdType("Patient/123/_history/2").withVersion("").getValue());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
|
|
|
@ -709,13 +709,15 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
|
|||
* Creates a new instance of this ID which is identical, but refers to the
|
||||
* specific version of this resource ID noted by theVersion.
|
||||
*
|
||||
* @param theVersion The actual version string, e.g. "1"
|
||||
* @param theVersion The actual version string, e.g. "1". If theVersion is blank or null, returns the same as {@link #toVersionless()}}
|
||||
* @return A new instance of IdType which is identical, but refers to the
|
||||
* specific version of this resource ID noted by theVersion.
|
||||
*/
|
||||
@Override
|
||||
public IdType withVersion(String theVersion) {
|
||||
Validate.notBlank(theVersion, "Version may not be null or empty");
|
||||
if (isBlank(theVersion)) {
|
||||
return toVersionless();
|
||||
}
|
||||
|
||||
if (isLocal() || isUrn()) {
|
||||
return new IdType(getValueAsString());
|
||||
|
|
|
@ -12,13 +12,13 @@ import static org.junit.Assert.*;
|
|||
|
||||
public class IdTypeR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IdTypeR4Test.class);
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IdTypeR4Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
private Patient parseAndEncode(Patient patient) {
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
ourLog.info("\n" + encoded);
|
||||
return ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -53,37 +53,97 @@ public class IdTypeR4Test {
|
|||
assertEquals("http://my.org/a/b/c/foo/_history/2", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUuid() {
|
||||
IdType id = new IdType("urn:uuid:1234-5678");
|
||||
assertEquals("urn:uuid:1234-5678", id.getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.getIdPart());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
public void testBigDecimalIds() {
|
||||
|
||||
IdType id = new IdType(new BigDecimal("123"));
|
||||
assertEquals(id.getIdPartAsBigDecimal(), new BigDecimal("123"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #67
|
||||
*/
|
||||
@Test
|
||||
public void testComplicatedLocal() {
|
||||
IdType id = new IdType("#Patient/cid:Patient-72/_history/1");
|
||||
assertTrue(id.isLocal());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
assertNull(id.getResourceType());
|
||||
assertNull(id.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id.getIdPart());
|
||||
|
||||
IdType id2 = new IdType("#Patient/cid:Patient-72/_history/1");
|
||||
assertEquals(id, id2);
|
||||
|
||||
id2 = id2.toUnqualified();
|
||||
assertTrue(id2.isLocal());
|
||||
assertNull(id2.getBaseUrl());
|
||||
assertNull(id2.getResourceType());
|
||||
assertNull(id2.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id2.getIdPart());
|
||||
|
||||
assertEquals("urn:uuid:1234-5678", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOid() {
|
||||
IdType id = new IdType("urn:oid:1.2.3.4");
|
||||
assertEquals("urn:oid:1.2.3.4", id.getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.getIdPart());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
public void testConstructorsWithNullArguments() {
|
||||
IdType id = new IdType(null, null, null);
|
||||
assertEquals(null, id.getValue());
|
||||
}
|
||||
|
||||
assertEquals("urn:oid:1.2.3.4", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withVersion("2").getValue());
|
||||
@Test
|
||||
public void testDetectLocal() {
|
||||
IdType id;
|
||||
|
||||
id = new IdType("#123");
|
||||
assertEquals("#123", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1");
|
||||
assertEquals("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("http://example.com/Patient/33#123");
|
||||
assertEquals("http://example.com/Patient/33#123", id.getValue());
|
||||
assertFalse(id.isLocal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocalBase() {
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetermineBase() {
|
||||
|
||||
IdType rr;
|
||||
|
||||
rr = new IdType("http://foo/fhir/Organization/123");
|
||||
assertEquals("http://foo/fhir", rr.getBaseUrl());
|
||||
|
||||
rr = new IdType("http://foo/fhir/Organization/123/_history/123");
|
||||
assertEquals("http://foo/fhir", rr.getBaseUrl());
|
||||
|
||||
rr = new IdType("Organization/123/_history/123");
|
||||
assertEquals(null, rr.getBaseUrl());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeParts() {
|
||||
IdType id = new IdType("http://foo", "Patient", "123", "456");
|
||||
assertEquals("http://foo/Patient/123/_history/456", id.getValue());
|
||||
assertEquals("http://foo/Patient/123/_history/9", id.withVersion("9").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -119,82 +179,19 @@ public class IdTypeR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocal() {
|
||||
IdType id;
|
||||
|
||||
id = new IdType("#123");
|
||||
assertEquals("#123", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1");
|
||||
assertEquals("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("http://example.com/Patient/33#123");
|
||||
assertEquals("http://example.com/Patient/33#123", id.getValue());
|
||||
assertFalse(id.isLocal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorsWithNullArguments() {
|
||||
IdType id = new IdType(null, null, null);
|
||||
assertEquals(null, id.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocalBase() {
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals(null, new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #67
|
||||
*/
|
||||
@Test
|
||||
public void testComplicatedLocal() {
|
||||
IdType id = new IdType("#Patient/cid:Patient-72/_history/1");
|
||||
assertTrue(id.isLocal());
|
||||
public void testOid() {
|
||||
IdType id = new IdType("urn:oid:1.2.3.4");
|
||||
assertEquals("urn:oid:1.2.3.4", id.getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.getIdPart());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:oid:1.2.3.4", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
assertNull(id.getResourceType());
|
||||
assertNull(id.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id.getIdPart());
|
||||
|
||||
IdType id2 = new IdType("#Patient/cid:Patient-72/_history/1");
|
||||
assertEquals(id, id2);
|
||||
|
||||
id2 = id2.toUnqualified();
|
||||
assertTrue(id2.isLocal());
|
||||
assertNull(id2.getBaseUrl());
|
||||
assertNull(id2.getResourceType());
|
||||
assertNull(id2.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id2.getIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetermineBase() {
|
||||
|
||||
IdType rr;
|
||||
|
||||
rr = new IdType("http://foo/fhir/Organization/123");
|
||||
assertEquals("http://foo/fhir", rr.getBaseUrl());
|
||||
|
||||
rr = new IdType("http://foo/fhir/Organization/123/_history/123");
|
||||
assertEquals("http://foo/fhir", rr.getBaseUrl());
|
||||
|
||||
rr = new IdType("Organization/123/_history/123");
|
||||
assertEquals(null, rr.getBaseUrl());
|
||||
|
||||
assertEquals("urn:oid:1.2.3.4", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:oid:1.2.3.4", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,14 +209,6 @@ public class IdTypeR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigDecimalIds() {
|
||||
|
||||
IdType id = new IdType(new BigDecimal("123"));
|
||||
assertEquals(id.getIdPartAsBigDecimal(), new BigDecimal("123"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueAbsoluteWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -235,30 +224,6 @@ public class IdTypeR4Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testViewMethods() {
|
||||
IdType i = new IdType("http://foo/fhir/Organization/123/_history/999");
|
||||
assertEquals("Organization/123/_history/999", i.toUnqualified().getValue());
|
||||
assertEquals("http://foo/fhir/Organization/123", i.toVersionless().getValue());
|
||||
assertEquals("Organization/123", i.toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("/123/_history/999");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals(null, ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
assertEquals(null, ref.getReferenceElement().getVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueMissingType1() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -301,13 +266,6 @@ public class IdTypeR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeParts() {
|
||||
IdType id = new IdType("http://foo", "Patient", "123", "456");
|
||||
assertEquals("http://foo/Patient/123/_history/456", id.getValue());
|
||||
assertEquals("http://foo/Patient/123/_history/9", id.withVersion("9").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueRelative2() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -322,10 +280,53 @@ public class IdTypeR4Test {
|
|||
|
||||
}
|
||||
|
||||
private Patient parseAndEncode(Patient patient) {
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
ourLog.info("\n" + encoded);
|
||||
return ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
||||
@Test
|
||||
public void testParseValueWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("/123/_history/999");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals(null, ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
assertEquals(null, ref.getReferenceElement().getVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUuid() {
|
||||
IdType id = new IdType("urn:uuid:1234-5678");
|
||||
assertEquals("urn:uuid:1234-5678", id.getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.getIdPart());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualified().getValueAsString());
|
||||
assertEquals("urn:uuid:1234-5678", id.toUnqualifiedVersionless().getValueAsString());
|
||||
assertEquals(null, id.getVersionIdPart());
|
||||
assertEquals(null, id.getResourceType());
|
||||
assertEquals(null, id.getBaseUrl());
|
||||
|
||||
assertEquals("urn:uuid:1234-5678", id.withResourceType("Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withServerBase("http://foo", "Patient").getValue());
|
||||
assertEquals("urn:uuid:1234-5678", id.withVersion("2").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testViewMethods() {
|
||||
IdType i = new IdType("http://foo/fhir/Organization/123/_history/999");
|
||||
assertEquals("Organization/123/_history/999", i.toUnqualified().getValue());
|
||||
assertEquals("http://foo/fhir/Organization/123", i.toVersionless().getValue());
|
||||
assertEquals("Organization/123", i.toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithVersionNull() {
|
||||
assertEquals("Patient/123", new IdType("Patient/123/_history/2").withVersion("").getValue());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
|
|
|
@ -78,6 +78,37 @@
|
|||
applies to the operation by name whether it is at the
|
||||
server, type, or instance level.
|
||||
</action>
|
||||
<action type="add">
|
||||
Calling <![CDATA[<code>IdType#withVersion(String)</code>]]>
|
||||
with a null/blank parameter will now return a copy of the
|
||||
ID with the version removed. Previously this call would
|
||||
deliberately cause an IllegalArgumentException.
|
||||
</action>
|
||||
<action type="fix">
|
||||
When updating resources on the JPA server, tags did not always
|
||||
consistently follow FHIR's recommended rules for tag retention. According
|
||||
to FHIR's rules, if a tag is not explicitly present on an update but
|
||||
was present on the previous version, it should be carried forward anyhow.
|
||||
Due to a bug, this happened when more than one tag was present
|
||||
but not when only one was present. This has been corrected. In
|
||||
addition, a new request header called
|
||||
<![CDATA[<code>X-Meta-Snapshot-Mode</code>]]>
|
||||
has been added that can be used by the client to override
|
||||
this behaviour.
|
||||
</action>
|
||||
<action type="fix">
|
||||
The JPA server's resource counts query has been optimized to
|
||||
give the database a bit more flexibility to
|
||||
optimize, which should increase performance for this query.
|
||||
</action>
|
||||
<action type="add">
|
||||
The JPA server CapabilityStatement generator has been tuned
|
||||
so that resource counts are no longer calculated synchronously
|
||||
as a part of building the CapabilityStatement response. With
|
||||
this change, counts are calculated in the background and cached
|
||||
which can yield significant performance improvements on
|
||||
hevaily loaded servers.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.3.0" date="2018-03-29">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue