From 9d70dbd08f36cd75d006612a54e1c07e996ecb65 Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Mon, 27 Feb 2023 12:58:27 -0500 Subject: [PATCH] Add UserSelected and Version to resource tag (#4591) * First commit: Add userSelected and version to ResourceTag and ResourceHistoryTag. Add migration step to migration tasks. For some reason SchemaMigrationTest is failing. * Fix nullability, update constructors, truncate versions over 30 chars. * yay we're done just cleanup * Checkpoint for recent changes. * Last commit before pausing work. * Fix bad code to find the version, tweak unit test pid ID to versionless and add TODO about why is update part of the test not passing? * Fix bad code in extractTagsRi(): Make it leverage the IBaseCoding variable already in the for loop. Fix bad code in populateResourceMetadataRi(). Leverage the existing BaseTag and use it to populate the IBaseCoding tag instance instead. Add more and better assertions in the unit test. * Merge rel_6_4 in * Current state for pairing * Fix CodingDt.getUserSelected method return code in tinder * Complete migration task and cleanup * Remove missed fixme * Bump version temporarily to use it for building core lib * Use primitive for compatibility with tinder generated CodingDt * Copyright updates * Hack to bypass NPE generated by bogus tinder-generated code * Simplify by removing temporary deprecations as version bump is needed anyway because of TagDefinition entity changes * Adjust tests * Fix migration task * Add test to show problem with tinder generated BooleanDt * More test adjustments * Improve BooleanDt NPE avoidance * Update core dep * Reverse Juan CVE VersionEnumTest changes. * Fix unit test. --------- Co-authored-by: Ken Stevens Co-authored-by: juan.marchionatto Co-authored-by: Tadgh --- .../main/java/ca/uhn/fhir/model/api/Tag.java | 7 +- ...ected-and-version-missing-in-database.yaml | 6 + .../ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java | 90 ++++++---- .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 12 +- .../jpa/dao/JpaStorageResourceParser.java | 2 + .../tasks/HapiFhirJpaMigrationTasks.java | 29 +++ .../fhir/jpa/model/entity/ResourceTable.java | 3 +- .../fhir/jpa/model/entity/TagDefinition.java | 44 ++++- .../jpa/model/entity/TagDefinitionTest.java | 11 +- .../export/ExpandResourcesStepJpaTest.java | 12 +- .../uhn/fhir/jpa/dao/BaseHapiFhirDaoTest.java | 21 ++- .../jpa/dao/r4/FhirResourceDaoR4MetaTest.java | 168 ++++++++++++++++++ .../fhir/jpa/util/MemoryCacheServiceTest.java | 7 +- .../uhn/fhir/jpa/util/MemoryCacheService.java | 8 +- pom.xml | 2 +- 15 files changed, 359 insertions(+), 63 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4204-default-config-meta-tags-user-selected-and-version-missing-in-database.yaml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java index 9f9a20d15ee..037c625315b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Tag.java @@ -19,15 +19,14 @@ package ca.uhn.fhir.model.api; * limitations under the License. * #L% */ -import static org.apache.commons.lang3.StringUtils.isNotBlank; - -import java.net.URI; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.hl7.fhir.instance.model.api.IBaseCoding; +import java.net.URI; + /** * A single tag *

@@ -115,12 +114,14 @@ public class Tag extends BaseElement implements IElement, IBaseCoding { return false; if (getClass() != obj.getClass()) return false; + Tag other = (Tag) obj; if (myScheme == null) { if (other.myScheme != null) return false; } else if (!myScheme.equals(other.myScheme)) return false; + if (myTerm == null) { if (other.myTerm != null) return false; diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4204-default-config-meta-tags-user-selected-and-version-missing-in-database.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4204-default-config-meta-tags-user-selected-and-version-missing-in-database.yaml new file mode 100644 index 00000000000..0bd40b3cd95 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4204-default-config-meta-tags-user-selected-and-version-missing-in-database.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 4204 +jira: SMILE-4688 +title: "With default configuration, Resource meta.tag properties: `userSelected` and `version`, were not stored in the database. + This is now fixed." diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index f3a8fc224c8..b9199137dce 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -126,6 +126,7 @@ import javax.persistence.PersistenceContextType; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.xml.stream.events.Characters; import javax.xml.stream.events.XMLEvent; @@ -143,7 +144,9 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.stream.Collectors; +import static java.util.Objects.isNull; import static java.util.Objects.nonNull; +import static org.apache.commons.lang3.BooleanUtils.isFalse; import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -276,7 +279,8 @@ public abstract class BaseHapiFhirDao extends BaseStora TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource); if (tagList != null) { for (Tag next : tagList) { - TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel()); + TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getScheme(), next.getTerm(), + next.getLabel(), next.getVersion(), next.getUserSelected()); if (def != null) { ResourceTag tag = theEntity.addTag(def); allDefs.add(tag); @@ -288,7 +292,8 @@ public abstract class BaseHapiFhirDao extends BaseStora List securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(theResource); if (securityLabels != null) { for (BaseCodingDt next : securityLabels) { - TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue()); + TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), + next.getCodeElement().getValue(), next.getDisplayElement().getValue(), null, null); if (def != null) { ResourceTag tag = theEntity.addTag(def); allDefs.add(tag); @@ -300,7 +305,7 @@ public abstract class BaseHapiFhirDao extends BaseStora List profiles = ResourceMetadataKeyEnum.PROFILES.get(theResource); if (profiles != null) { for (IIdType next : profiles) { - TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null); + TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null, null, null); if (def != null) { ResourceTag tag = theEntity.addTag(def); allDefs.add(tag); @@ -314,7 +319,8 @@ public abstract class BaseHapiFhirDao extends BaseStora List tagList = theResource.getMeta().getTag(); if (tagList != null) { for (IBaseCoding next : tagList) { - TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay()); + TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getSystem(), next.getCode(), + next.getDisplay(), next.getVersion(), next.getUserSelected()); if (def != null) { ResourceTag tag = theEntity.addTag(def); theAllTags.add(tag); @@ -326,7 +332,7 @@ public abstract class BaseHapiFhirDao extends BaseStora List securityLabels = theResource.getMeta().getSecurity(); if (securityLabels != null) { for (IBaseCoding next : securityLabels) { - TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay()); + TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay(), null, null); if (def != null) { ResourceTag tag = theEntity.addTag(def); theAllTags.add(tag); @@ -338,7 +344,7 @@ public abstract class BaseHapiFhirDao extends BaseStora List> profiles = theResource.getMeta().getProfile(); if (profiles != null) { for (IPrimitiveType next : profiles) { - TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null); + TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null, null, null); if (def != null) { ResourceTag tag = theEntity.addTag(def); theAllTags.add(tag); @@ -376,22 +382,25 @@ public abstract class BaseHapiFhirDao extends BaseStora /** * null will only be returned if the scheme and tag are both blank */ - protected TagDefinition getTagOrNull(TransactionDetails theTransactionDetails, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) { + protected TagDefinition getTagOrNull(TransactionDetails theTransactionDetails, TagTypeEnum theTagType, String theScheme, + String theTerm, String theLabel, String theVersion, Boolean theUserSelected) { if (isBlank(theScheme) && isBlank(theTerm) && isBlank(theLabel)) { return null; } - MemoryCacheService.TagDefinitionCacheKey key = toTagDefinitionMemoryCacheKey(theTagType, theScheme, theTerm); + MemoryCacheService.TagDefinitionCacheKey key = toTagDefinitionMemoryCacheKey(theTagType, theScheme, theTerm, theVersion, theUserSelected); TagDefinition retVal = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.TAG_DEFINITION, key); if (retVal == null) { - HashMap resolvedTagDefinitions = theTransactionDetails.getOrCreateUserData(HapiTransactionService.XACT_USERDATA_KEY_RESOLVED_TAG_DEFINITIONS, () -> new HashMap<>()); + HashMap resolvedTagDefinitions = theTransactionDetails + .getOrCreateUserData(HapiTransactionService.XACT_USERDATA_KEY_RESOLVED_TAG_DEFINITIONS, HashMap::new); + retVal = resolvedTagDefinitions.get(key); if (retVal == null) { // actual DB hit(s) happen here - retVal = getOrCreateTag(theTagType, theScheme, theTerm, theLabel); + retVal = getOrCreateTag(theTagType, theScheme, theTerm, theLabel, theVersion, theUserSelected); TransactionSynchronization sync = new AddTagDefinitionToCacheAfterCommitSynchronization(key, retVal); TransactionSynchronizationManager.registerSynchronization(sync); @@ -409,26 +418,10 @@ public abstract class BaseHapiFhirDao extends BaseStora *

* Can also throw an InternalErrorException if something bad happens. */ - private TagDefinition getOrCreateTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) { - CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); - CriteriaQuery cq = builder.createQuery(TagDefinition.class); - Root from = cq.from(TagDefinition.class); + private TagDefinition getOrCreateTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel, + String theVersion, Boolean theUserSelected) { - if (isNotBlank(theScheme)) { - cq.where( - builder.and( - builder.equal(from.get("myTagType"), theTagType), - builder.equal(from.get("mySystem"), theScheme), - builder.equal(from.get("myCode"), theTerm))); - } else { - cq.where( - builder.and( - builder.equal(from.get("myTagType"), theTagType), - builder.isNull(from.get("mySystem")), - builder.equal(from.get("myCode"), theTerm))); - } - - TypedQuery q = myEntityManager.createQuery(cq); + TypedQuery q = buildTagQuery(theTagType, theScheme, theTerm, theVersion, theUserSelected); TransactionTemplate template = new TransactionTemplate(myTransactionManager); template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); @@ -450,6 +443,8 @@ public abstract class BaseHapiFhirDao extends BaseStora val = q.getSingleResult(); } catch (NoResultException e) { val = new TagDefinition(theTagType, theScheme, theTerm, theLabel); + val.setVersion(theVersion); + val.setUserSelected(theUserSelected); myEntityManager.persist(val); } return val; @@ -507,6 +502,34 @@ public abstract class BaseHapiFhirDao extends BaseStora return retVal; } + private TypedQuery buildTagQuery(TagTypeEnum theTagType, String theScheme, String theTerm, + String theVersion, Boolean theUserSelected) { + CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); + CriteriaQuery cq = builder.createQuery(TagDefinition.class); + Root from = cq.from(TagDefinition.class); + + List predicates = new ArrayList<>(); + predicates.add( + builder.and( + builder.equal(from.get("myTagType"), theTagType), + builder.equal(from.get("myCode"), theTerm))); + + predicates.add( isBlank(theScheme) + ? builder.isNull(from.get("mySystem")) + : builder.equal(from.get("mySystem"), theScheme)); + + predicates.add( isBlank(theVersion) + ? builder.isNull(from.get("myVersion")) + : builder.equal(from.get("myVersion"), theVersion)); + + predicates.add( isNull(theUserSelected) || isFalse(theUserSelected) + ? builder.isFalse(from.get("myUserSelected")) + : builder.isTrue(from.get("myUserSelected"))); + + cq.where(predicates.toArray(new Predicate[0])); + return myEntityManager.createQuery(cq); + } + void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) { String newVersion; @@ -741,10 +764,10 @@ public abstract class BaseHapiFhirDao extends BaseStora } RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); - if (def.isStandardType() == false) { + if ( ! def.isStandardType()) { String profile = def.getResourceProfile(""); if (isNotBlank(profile)) { - TagDefinition profileDef = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null); + TagDefinition profileDef = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null, null, null); ResourceTag tag = theEntity.addTag(profileDef); allDefs.add(tag); @@ -1584,8 +1607,9 @@ public abstract class BaseHapiFhirDao extends BaseStora } @Nonnull - public static MemoryCacheService.TagDefinitionCacheKey toTagDefinitionMemoryCacheKey(TagTypeEnum theTagType, String theScheme, String theTerm) { - return new MemoryCacheService.TagDefinitionCacheKey(theTagType, theScheme, theTerm); + public static MemoryCacheService.TagDefinitionCacheKey toTagDefinitionMemoryCacheKey( + TagTypeEnum theTagType, String theScheme, String theTerm, String theVersion, Boolean theUserSelected) { + return new MemoryCacheService.TagDefinitionCacheKey(theTagType, theScheme, theTerm, theVersion, theUserSelected); } static String cleanProvenanceSourceUri(String theProvenanceSourceUri) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 2c1d92e7d35..9e9750b198f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -143,6 +143,7 @@ import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -740,9 +741,11 @@ public abstract class BaseHapiFhirResourceDao extends B boolean hasTag = false; for (BaseTag next : new ArrayList<>(theEntity.getTags())) { - if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) && - ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) && - ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) { + if (Objects.equals(next.getTag().getTagType(), nextDef.getTagType()) && + Objects.equals(next.getTag().getSystem(), nextDef.getSystem()) && + Objects.equals(next.getTag().getCode(), nextDef.getCode()) && + Objects.equals(next.getTag().getVersion(), nextDef.getVersion()) && + Objects.equals(next.getTag().getUserSelected(), nextDef.getUserSelected())) { hasTag = true; break; } @@ -751,7 +754,8 @@ public abstract class BaseHapiFhirResourceDao extends B if (!hasTag) { theEntity.setHasTags(true); - TagDefinition def = getTagOrNull(theTransactionDetails, nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay()); + TagDefinition def = getTagOrNull(theTransactionDetails, nextDef.getTagType(), nextDef.getSystem(), + nextDef.getCode(), nextDef.getDisplay(), nextDef.getVersion(), nextDef.getUserSelected()); if (def != null) { BaseTag newEntity = theEntity.addTag(def); if (newEntity.getTagId() == null) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java index 45e53ec091a..f92f5dde7cb 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java @@ -431,6 +431,8 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser { tag.setSystem(next.getTag().getSystem()); tag.setCode(next.getTag().getCode()); tag.setDisplay(next.getTag().getDisplay()); + tag.setVersion(next.getTag().getVersion()); + tag.setUserSelected(next.getTag().getUserSelected()); break; } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index d79bac1db1f..9679089610a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -91,9 +91,38 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { } protected void init640() { + Builder version = forVersion(VersionEnum.V6_4_0); + + { + Builder.BuilderWithTableName tagDefTable = version.onTable("HFJ_TAG_DEF"); + + // add columns + tagDefTable + .addColumn("20230209.1", "TAG_VERSION") + .nullable() + .type(ColumnTypeEnum.STRING, 30); + tagDefTable + .addColumn("20230209.2", "TAG_USER_SELECTED") + .nullable() + .type(ColumnTypeEnum.BOOLEAN); + + // Update indexing + tagDefTable.dropIndex("20230209.3", "IDX_TAGDEF_TYPESYSCODE"); + + tagDefTable.dropIndex("20230209.4", "IDX_TAGDEF_TYPESYSCODEVERUS"); + Map addTagDefConstraint = new HashMap<>(); + addTagDefConstraint.put(DriverTypeEnum.H2_EMBEDDED, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)"); + addTagDefConstraint.put(DriverTypeEnum.MARIADB_10_1, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)"); + addTagDefConstraint.put(DriverTypeEnum.MSSQL_2012, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)"); + addTagDefConstraint.put(DriverTypeEnum.MYSQL_5_7, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)"); + addTagDefConstraint.put(DriverTypeEnum.ORACLE_12C, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)"); + addTagDefConstraint.put(DriverTypeEnum.POSTGRES_9_4, "ALTER TABLE HFJ_TAG_DEF ADD CONSTRAINT IDX_TAGDEF_TYPESYSCODEVERUS UNIQUE (TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_VERSION, TAG_USER_SELECTED)"); + version.executeRawSql("20230209.5", addTagDefConstraint); + } } + protected void init630() { Builder version = forVersion(VersionEnum.V6_3_0); diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java index 6ab566718d1..cddb914261d 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java @@ -32,10 +32,10 @@ import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; -import org.hibernate.annotations.GenericGenerator; import org.hibernate.Session; import org.hibernate.annotations.GenerationTime; import org.hibernate.annotations.GeneratorType; +import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.OptimisticLock; import org.hibernate.search.engine.backend.types.Projectable; import org.hibernate.search.engine.backend.types.Searchable; @@ -64,7 +64,6 @@ import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.PrePersist; import javax.persistence.PreUpdate; -import org.hibernate.annotations.GenericGenerator; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.Version; diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java index c2cf7755498..39a3c52f61b 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java @@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.model.entity; * #L% */ +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; @@ -49,7 +50,8 @@ import java.util.Collection; @Index(name = "IDX_TAG_DEF_TP_CD_SYS", columnList = "TAG_TYPE, TAG_CODE, TAG_SYSTEM, TAG_ID"), }, uniqueConstraints = { - @UniqueConstraint(name = "IDX_TAGDEF_TYPESYSCODE", columnNames = {"TAG_TYPE", "TAG_SYSTEM", "TAG_CODE"}) + @UniqueConstraint(name = "IDX_TAGDEF_TYPESYSCODEVERUS", + columnNames = {"TAG_TYPE", "TAG_SYSTEM", "TAG_CODE", "TAG_VERSION", "TAG_USER_SELECTED"}) } ) public class TagDefinition implements Serializable { @@ -57,22 +59,35 @@ public class TagDefinition implements Serializable { private static final long serialVersionUID = 1L; @Column(name = "TAG_CODE", length = 200) private String myCode; + @Column(name = "TAG_DISPLAY", length = 200) private String myDisplay; + @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_TAGDEF_ID") @SequenceGenerator(name = "SEQ_TAGDEF_ID", sequenceName = "SEQ_TAGDEF_ID") @Column(name = "TAG_ID") private Long myId; + @OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "myTag") private Collection myResources; + @OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "myTag") private Collection myResourceVersions; + @Column(name = "TAG_SYSTEM", length = 200) private String mySystem; + @Column(name = "TAG_TYPE", nullable = false) @Enumerated(EnumType.ORDINAL) private TagTypeEnum myTagType; + + @Column(name = "TAG_VERSION", length = 30) + private String myVersion; + + @Column(name = "TAG_USER_SELECTED") + private boolean myUserSelected; + @Transient private transient Integer myHashCode; @@ -133,6 +148,27 @@ public class TagDefinition implements Serializable { myHashCode = null; } + public String getVersion() { + return myVersion; + } + + public void setVersion(String theVersion) { + setVersionAfterTrim(theVersion); + } + + private void setVersionAfterTrim(String theVersion) { + if (theVersion != null) { + myVersion = StringUtils.truncate(theVersion, 30); + } + } + + public Boolean getUserSelected() { return myUserSelected; } + + public void setUserSelected(Boolean theUserSelected) { + myUserSelected = theUserSelected != null && theUserSelected; + } + + @Override public boolean equals(Object obj) { if (this == obj) { @@ -151,6 +187,8 @@ public class TagDefinition implements Serializable { b.append(myTagType, other.myTagType); b.append(mySystem, other.mySystem); b.append(myCode, other.myCode); + b.append(myVersion, other.myVersion); + b.append(myUserSelected, other.myUserSelected); } return b.isEquals(); @@ -163,6 +201,8 @@ public class TagDefinition implements Serializable { b.append(myTagType); b.append(mySystem); b.append(myCode); + b.append(myVersion); + b.append(myUserSelected); myHashCode = b.toHashCode(); } return myHashCode; @@ -175,6 +215,8 @@ public class TagDefinition implements Serializable { retVal.append("system", mySystem); retVal.append("code", myCode); retVal.append("display", myDisplay); + retVal.append("version", myVersion); + retVal.append("userSelected", myUserSelected); return retVal.build(); } } diff --git a/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/entity/TagDefinitionTest.java b/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/entity/TagDefinitionTest.java index d5cd0432175..c2c19815585 100644 --- a/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/entity/TagDefinitionTest.java +++ b/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/entity/TagDefinitionTest.java @@ -13,7 +13,11 @@ public class TagDefinitionTest { def.setCode("my_code"); def.setSystem("my_system"); def.setDisplay("my_display"); - assertEquals("TagDefinition[id=,system=my_system,code=my_code,display=my_display]", def.toString()); + def.setVersion("V 1.0"); + def.setUserSelected(true); + assertEquals( + "TagDefinition[id=,system=my_system,code=my_code,display=my_display,version=V 1.0,userSelected=true]", + def.toString()); } @Test @@ -39,7 +43,8 @@ public class TagDefinitionTest { def.setCode("my_code"); def.setSystem("my_system"); def.setDisplay("my_display"); - assertEquals (-2125810377,def.hashCode()); - assertEquals (-2125810377,def.hashCode()); + def.setVersion("V 1.0"); + def.setUserSelected(true); + assertEquals (434166476,def.hashCode()); } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/export/ExpandResourcesStepJpaTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/export/ExpandResourcesStepJpaTest.java index f99a8769215..f7919a1d068 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/export/ExpandResourcesStepJpaTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/export/ExpandResourcesStepJpaTest.java @@ -65,8 +65,8 @@ public class ExpandResourcesStepJpaTest extends BaseJpaR4Test { .boxed() .map(t -> { Patient p = new Patient(); - p.getMeta().addTag().setSystem("http://static").setCode("tag"); - p.getMeta().addTag().setSystem("http://dynamic").setCode("tag" + t); + p.getMeta().addTag().setSystem("http://static").setCode("tag").setUserSelected(true).setVersion("1"); + p.getMeta().addTag().setSystem("http://dynamic").setCode("tag" + t).setUserSelected(true).setVersion("1"); return myPatientDao.create(p, mySrd).getId().getIdPartAsLong(); }).toList(); assertEquals(count, ids.size()); @@ -91,10 +91,10 @@ public class ExpandResourcesStepJpaTest extends BaseJpaR4Test { verify(mySink, times(1)).accept(myWorkChunkCaptor.capture()); ExpandedResourcesList expandedResourceList = myWorkChunkCaptor.getValue(); assertEquals(10, expandedResourceList.getStringifiedResources().size()); - assertThat(expandedResourceList.getStringifiedResources().get(0), containsString("{\"system\":\"http://static\",\"code\":\"tag\"}")); - assertThat(expandedResourceList.getStringifiedResources().get(0), containsString("{\"system\":\"http://dynamic\",\"code\":\"tag0\"}")); - assertThat(expandedResourceList.getStringifiedResources().get(1), containsString("{\"system\":\"http://static\",\"code\":\"tag\"}")); - assertThat(expandedResourceList.getStringifiedResources().get(1), containsString("{\"system\":\"http://dynamic\",\"code\":\"tag1\"}")); + assertThat(expandedResourceList.getStringifiedResources().get(0), containsString("{\"system\":\"http://static\",\"version\":\"1\",\"code\":\"tag\",\"userSelected\":true}")); + assertThat(expandedResourceList.getStringifiedResources().get(0), containsString("{\"system\":\"http://static\",\"version\":\"1\",\"code\":\"tag\",\"userSelected\":true}")); + assertThat(expandedResourceList.getStringifiedResources().get(1), containsString("{\"system\":\"http://static\",\"version\":\"1\",\"code\":\"tag\",\"userSelected\":true}")); + assertThat(expandedResourceList.getStringifiedResources().get(1), containsString("{\"system\":\"http://static\",\"version\":\"1\",\"code\":\"tag\",\"userSelected\":true}")); // Verify query counts assertEquals(theExpectedSelectQueries, myCaptureQueriesListener.countSelectQueries()); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDaoTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDaoTest.java index ad9c58d08c0..846c392fd9a 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDaoTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDaoTest.java @@ -77,12 +77,14 @@ public class BaseHapiFhirDaoTest { TagTypeEnum theEnum, String theScheme, String theTerm, - String theLabel) { + String theLabel, + String theVersion, + Boolean theUserSelected ) { // we need to init synchronization due to what // the underlying class is doing try { TransactionSynchronizationManager.initSynchronization(); - return super.getTagOrNull(theDetails, theEnum, theScheme, theTerm, theLabel); + return super.getTagOrNull(theDetails, theEnum, theScheme, theTerm, theLabel, theVersion, theUserSelected); } finally { TransactionSynchronizationManager.clearSynchronization(); } @@ -175,12 +177,13 @@ public class BaseHapiFhirDaoTest { String scheme = "http://localhost"; String term = "code123"; String label = "hollow world"; + String version = "v1.0"; + Boolean userSelected = true; String raceConditionError = "Entity exists; if this is logged, you have race condition issues!"; - TagDefinition tagDefinition = new TagDefinition(tagType, - scheme, - term, - label); + TagDefinition tagDefinition = new TagDefinition(tagType, scheme, term, label); + tagDefinition.setVersion(version); + tagDefinition.setUserSelected(userSelected); // mock objects CriteriaBuilder builder = getMockedCriteriaBuilder(); @@ -270,7 +273,7 @@ public class BaseHapiFhirDaoTest { Runnable task = () -> { latch.countDown(); try { - TagDefinition retTag = myTestDao.getTagOrNull(new TransactionDetails(), tagType, scheme, term, label); + TagDefinition retTag = myTestDao.getTagOrNull(new TransactionDetails(), tagType, scheme, term, label, version, userSelected); outcomes.put(retTag.hashCode(), retTag); counter.incrementAndGet(); } catch (Exception ex) { @@ -330,6 +333,8 @@ public class BaseHapiFhirDaoTest { String scheme = "http://localhost"; String term = "code123"; String label = "hollow world"; + String version = "v1.0"; + Boolean userSelected = true; TransactionDetails transactionDetails = new TransactionDetails(); String exMsg = "Hi there"; String readError = "No read for you"; @@ -358,7 +363,7 @@ public class BaseHapiFhirDaoTest { // test try { - myTestDao.getTagOrNull(transactionDetails, tagType, scheme, term, label); + myTestDao.getTagOrNull(transactionDetails, tagType, scheme, term, label, version, userSelected); fail(); } catch (Exception ex) { // verify diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4MetaTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4MetaTest.java index 0add9706872..931f5c64de8 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4MetaTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4MetaTest.java @@ -1,12 +1,17 @@ package ca.uhn.fhir.jpa.dao.r4; +import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag; +import ca.uhn.fhir.jpa.model.entity.TagDefinition; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.system.HapiTestSystemProperties; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.InstantType; import org.hl7.fhir.r4.model.Meta; import org.hl7.fhir.r4.model.Patient; @@ -14,12 +19,16 @@ import org.hl7.fhir.r4.model.StringType; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -29,7 +38,9 @@ import java.util.stream.Collectors; import static ca.uhn.fhir.rest.api.Constants.PARAM_TAG; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -142,6 +153,163 @@ public class FhirResourceDaoR4MetaTest extends BaseJpaR4Test { assertEquals("bar", patient2.getMeta().getSecurityFirstRep().getCode()); } + @Nested + public class TestTagWithVersionAndUserSelected { + + private static final String expectedSystem1 = "http://foo"; + private static final String expectedCode1 = "code1"; + private static final String expectedVersion1 = "testVersion1"; + private static final String expectedDisplay1 = "Test1"; + private static final boolean expectedUserSelected1 = true; + + private static final String expectedSystem2 = "http://another.system"; + private static final String expectedCode2 = "code2"; + private static final String expectedVersion2 = "testVersion2"; + private static final String expectedDisplay2 = "Test2"; + private static final boolean expectedUserSelected2 = false; + + private static final class TagQtyExpectations { + public int theTagQty; + public int theTagV1Qty; + public int theTagV2Qty; + + public TagQtyExpectations(int theTheTagV1Qty, int theTheTagV2Qty) { + theTagQty = theTheTagV1Qty + theTheTagV2Qty; + theTagV1Qty = theTheTagV1Qty; + theTagV2Qty = theTheTagV2Qty; + } + } + + private static final Map expectedTagCountMap = Map.of( + DaoConfig.TagStorageModeEnum.INLINE, new TagQtyExpectations(0, 1), + DaoConfig.TagStorageModeEnum.NON_VERSIONED, new TagQtyExpectations(1, 1), + DaoConfig.TagStorageModeEnum.VERSIONED, new TagQtyExpectations(1, 1) + ); + + private static final Map expectedHistoryTagCountMap = Map.of( + DaoConfig.TagStorageModeEnum.INLINE, new TagQtyExpectations(0, 0), + DaoConfig.TagStorageModeEnum.NON_VERSIONED, new TagQtyExpectations(0, 0), + DaoConfig.TagStorageModeEnum.VERSIONED, new TagQtyExpectations(2, 1) + ); + + @ParameterizedTest + @EnumSource(DaoConfig.TagStorageModeEnum.class) + public void testAddTagWithVersionAndUserSelected(DaoConfig.TagStorageModeEnum theTagStorageModeEnum) { + + myDaoConfig.setTagStorageMode(theTagStorageModeEnum); + + final Patient savedPatient = new Patient(); + final Coding newTag = savedPatient.getMeta() + .addTag() + .setSystem(expectedSystem1) + .setCode(expectedCode1) + .setDisplay(expectedDisplay1); + assertFalse(newTag.getUserSelected()); + newTag.setVersion(expectedVersion1) + .setUserSelected(expectedUserSelected1); + savedPatient.setActive(true); + final IIdType pid1 = myPatientDao.create(savedPatient, new SystemRequestDetails()).getId().toVersionless(); + + final Patient retrievedPatient = myPatientDao.read(pid1, new SystemRequestDetails()); + validateSavedPatientTags(retrievedPatient); + + // Update the patient to create a ResourceHistoryTag record + final List tagsFromDbPatient = retrievedPatient.getMeta().getTag(); + assertEquals(1, tagsFromDbPatient.size()); + + tagsFromDbPatient.get(0) + .setCode(expectedCode2) + .setSystem(expectedSystem2) + .setVersion(expectedVersion2) + .setDisplay(expectedDisplay2) + .setUserSelected(expectedUserSelected2); + + myPatientDao.update(retrievedPatient, new SystemRequestDetails()); + final Patient retrievedUpdatedPatient = myPatientDao.read(pid1, new SystemRequestDetails()); + + final Meta meta = retrievedUpdatedPatient.getMeta(); + final List tags = meta.getTag(); + tags.forEach(innerTag -> ourLog.info("TAGS: version: {}, userSelected: {}, code: {}, display: {}, system: {}", + innerTag.getVersion(), innerTag.getUserSelected(), innerTag.getCode(), innerTag.getDisplay(), innerTag.getSystem())); + final Coding tagFirstRep = meta.getTagFirstRep(); + ourLog.info("TAG FIRST REP: version: {}, userSelected: {}, code: {}, display: {}, system: {}", + tagFirstRep.getVersion(), tagFirstRep.getUserSelected(), tagFirstRep.getCode(), tagFirstRep.getDisplay(), tagFirstRep.getSystem()); + + TagQtyExpectations expectedCounts = expectedTagCountMap.get(theTagStorageModeEnum); + validateUpdatedPatientTags(expectedCounts, tags); + + final List resourceHistoryTags2 = myResourceHistoryTagDao.findAll(); + + resourceHistoryTags2.forEach(historyTag -> { + final TagDefinition tag = historyTag.getTag(); + ourLog.info("tagId: {}, resourceId: {}, version: {}, userSelected: {}, system: {}, code: {}, display: {}", + historyTag.getTagId(), historyTag.getResourceId(), tag.getVersion(), tag.getUserSelected(), tag.getSystem(), tag.getCode(), tag.getDisplay()); + }); + + TagQtyExpectations expectedHistoryCounts = expectedHistoryTagCountMap.get(theTagStorageModeEnum); + validateHistoryTags(expectedHistoryCounts, resourceHistoryTags2); + } + + + private void validateSavedPatientTags(Patient thePatient) { + assertAll( + () -> assertEquals(1, thePatient.getMeta().getTag().size()), + () -> assertEquals(0, thePatient.getMeta().getSecurity().size()), + () -> assertEquals(0, thePatient.getMeta().getProfile().size()), + + () -> assertEquals(expectedSystem1, thePatient.getMeta().getTagFirstRep().getSystem()), + () -> assertTrue(thePatient.getMeta().getTagFirstRep().getUserSelected()), + () -> assertEquals(expectedCode1, thePatient.getMeta().getTagFirstRep().getCode()), + () -> assertEquals(expectedVersion1, thePatient.getMeta().getTagFirstRep().getVersion()), + () -> assertEquals(expectedUserSelected1, thePatient.getMeta().getTagFirstRep().getUserSelected()) + ); + } + + + private void validateUpdatedPatientTags(TagQtyExpectations theExpectedCounts, List tags) { + assertAll( + () -> assertEquals(theExpectedCounts.theTagQty, tags.size()), + () -> assertEquals(theExpectedCounts.theTagV1Qty, tags.stream() + .filter(tag -> expectedSystem1.equals(tag.getSystem())) + .filter(tag -> expectedCode1.equals(tag.getCode())) + .filter(tag -> expectedDisplay1.equals(tag.getDisplay())) + .filter(tag -> expectedVersion1.equals(tag.getVersion())) + .filter(tag -> expectedUserSelected1 == tag.getUserSelected()) + .count()), + () -> assertEquals(theExpectedCounts.theTagV2Qty, tags.stream() + .filter(tag -> expectedSystem2.equals(tag.getSystem())) + .filter(tag -> expectedCode2.equals(tag.getCode())) + .filter(tag -> expectedDisplay2.equals(tag.getDisplay())) + .filter(tag -> expectedVersion2.equals(tag.getVersion())) + .filter(tag -> expectedUserSelected2 == tag.getUserSelected()) + .count()) + ); + } + + private void validateHistoryTags(TagQtyExpectations theExpectedHistoryCounts, List theHistoryTags) { + // validating this way because tags are a set so can be in any order + assertAll( + () -> assertEquals(theExpectedHistoryCounts.theTagQty, theHistoryTags.size()), + () -> assertEquals(theExpectedHistoryCounts.theTagV1Qty, theHistoryTags.stream() + .filter(resourceHistoryTag -> expectedSystem1.equals(resourceHistoryTag.getTag().getSystem())) + .filter(resourceHistoryTag -> expectedCode1.equals(resourceHistoryTag.getTag().getCode())) + .filter(resourceHistoryTag -> expectedDisplay1.equals(resourceHistoryTag.getTag().getDisplay())) + .filter(resourceHistoryTag -> expectedVersion1.equals(resourceHistoryTag.getTag().getVersion())) + .filter(resourceHistoryTag -> expectedUserSelected1 == resourceHistoryTag.getTag().getUserSelected()) + .count()), + () -> assertEquals(theExpectedHistoryCounts.theTagV2Qty, theHistoryTags.stream() + .filter(resourceHistoryTag -> expectedSystem2.equals(resourceHistoryTag.getTag().getSystem())) + .filter(resourceHistoryTag -> expectedCode2.equals(resourceHistoryTag.getTag().getCode())) + .filter(resourceHistoryTag -> expectedDisplay2.equals(resourceHistoryTag.getTag().getDisplay())) + .filter(resourceHistoryTag -> expectedVersion2.equals(resourceHistoryTag.getTag().getVersion())) + .filter(resourceHistoryTag -> expectedUserSelected2 == resourceHistoryTag.getTag().getUserSelected()) + .count()) + ); + } + + + } + @Disabled // TODO JA: This test fails regularly, need to get a dedicated connection pool for tag creation @Test diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/util/MemoryCacheServiceTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/util/MemoryCacheServiceTest.java index 167ae699814..4a23a9e64c5 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/util/MemoryCacheServiceTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/util/MemoryCacheServiceTest.java @@ -47,13 +47,18 @@ class MemoryCacheServiceTest { String system = "http://example.com"; TagTypeEnum type = TagTypeEnum.TAG; String code = "t"; + String version = "Ver 3.0"; + Boolean userSelected = true; - MemoryCacheService.TagDefinitionCacheKey cacheKey = new MemoryCacheService.TagDefinitionCacheKey(type, system, code); + MemoryCacheService.TagDefinitionCacheKey cacheKey = new MemoryCacheService.TagDefinitionCacheKey( + type, system, code, version, userSelected); TagDefinition retVal = mySvc.getIfPresent(MemoryCacheService.CacheEnum.TAG_DEFINITION, cacheKey); assertThat(retVal, nullValue()); TagDefinition tagDef = new TagDefinition(type, system, code, "theLabel"); + tagDef.setVersion(version); + tagDef.setUserSelected(userSelected); mySvc.put(MemoryCacheService.CacheEnum.TAG_DEFINITION, cacheKey, tagDef); retVal = mySvc.getIfPresent(MemoryCacheService.CacheEnum.TAG_DEFINITION, cacheKey); diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java index cef7f02513d..7a3fb8d3222 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java @@ -217,16 +217,22 @@ public class MemoryCacheService { private final TagTypeEnum myType; private final String mySystem; private final String myCode; + private final String myVersion; + private Boolean myUserSelected; private final int myHashCode; - public TagDefinitionCacheKey(TagTypeEnum theType, String theSystem, String theCode) { + public TagDefinitionCacheKey(TagTypeEnum theType, String theSystem, String theCode, String theVersion, Boolean theUserSelected) { myType = theType; mySystem = theSystem; myCode = theCode; + myVersion = theVersion; + myUserSelected = theUserSelected; myHashCode = new HashCodeBuilder(17, 37) .append(myType) .append(mySystem) .append(myCode) + .append(myVersion) + .append(myUserSelected) .toHashCode(); } diff --git a/pom.xml b/pom.xml index d61631903c1..7ba5ea936cd 100644 --- a/pom.xml +++ b/pom.xml @@ -864,7 +864,7 @@ - 5.6.97 + 5.6.971 1.0.3 -Dfile.encoding=UTF-8 -Xmx2048m