From e28972695ef963312c850e9dfaac4b5edfdee941 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Fri, 16 May 2025 09:59:45 -0700 Subject: [PATCH 01/17] Issue 52824: remove domain from cache if it's being updated --- .../api/audit/AbstractAuditTypeProvider.java | 9 ++++-- .../org/labkey/api/exp/OntologyManager.java | 30 ++++++++++++++++--- .../labkey/api/exp/property/DomainUtil.java | 3 +- .../api/exp/property/PropertyService.java | 6 ++++ .../labkey/api/assay/plate/PlateService.java | 2 +- .../org/labkey/assay/AssayUpgradeCode.java | 4 +-- .../src/org/labkey/assay/PlateController.java | 2 +- .../plate/AssayPlateMetadataServiceImpl.java | 18 +++++------ .../org/labkey/assay/plate/PlateManager.java | 19 ++++++++---- .../labkey/assay/plate/query/WellTable.java | 2 +- .../api/property/PropertyServiceImpl.java | 19 +++++++++++- 11 files changed, 86 insertions(+), 28 deletions(-) diff --git a/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java b/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java index b3a8e48c274..49b548bcc6f 100644 --- a/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java +++ b/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java @@ -121,7 +121,7 @@ protected AbstractAuditDomainKind getDomainKind() public void initializeProvider(User user) { AbstractAuditDomainKind domainKind = getDomainKind(); - Domain domain = getDomain(); + Domain domain = getDomain(true); // if the domain doesn't exist, create it if (domain == null) @@ -296,12 +296,17 @@ private void copyTo(DomainProperty dp, PropertyDescriptor pd, Container c) @Override public final Domain getDomain() + { + return getDomain(false); + } + + protected Domain getDomain(boolean forUpdate) { DomainKind domainKind = getDomainKind(); String domainURI = domainKind.generateDomainURI(QUERY_SCHEMA_NAME, getEventName(), getDomainContainer(), null); - return PropertyService.get().getDomain(getDomainContainer(), domainURI); + return PropertyService.get().getDomain(getDomainContainer(), domainURI, forUpdate); } diff --git a/api/src/org/labkey/api/exp/OntologyManager.java b/api/src/org/labkey/api/exp/OntologyManager.java index 9bb15813220..4d5a258f526 100644 --- a/api/src/org/labkey/api/exp/OntologyManager.java +++ b/api/src/org/labkey/api/exp/OntologyManager.java @@ -2443,25 +2443,47 @@ public DomainDescriptor load(@NotNull Integer key, @Nullable Object argument) } } - public static DomainDescriptor getDomainDescriptor(int id) { - return DOMAIN_DESC_BY_ID_CACHE.get(id); + return getDomainDescriptor(id, false); + } + + public static DomainDescriptor getDomainDescriptor(int id, boolean forUpdate) + { + DomainDescriptor dd = DOMAIN_DESC_BY_ID_CACHE.get(id); + if (forUpdate) + DOMAIN_DESC_BY_ID_CACHE.remove(id); + return dd; } @Nullable public static DomainDescriptor getDomainDescriptor(String domainURI, Container c) + { + return getDomainDescriptor(domainURI, c, false); + } + + @Nullable + public static DomainDescriptor getDomainDescriptor(String domainURI, Container c, boolean forUpdate) { if (c == null) return null; // cache lookup by project. if not found at project level, check to see if global - DomainDescriptor dd = DOMAIN_DESCRIPTORS_BY_URI_CACHE.get(getCacheKey(domainURI, c)); + Pair key = getCacheKey(domainURI, c); + DomainDescriptor dd = DOMAIN_DESCRIPTORS_BY_URI_CACHE.get(key); if (null != dd) + { + if (forUpdate) + DOMAIN_DESCRIPTORS_BY_URI_CACHE.remove(key); return dd; + } // Try in the /Shared container too - return DOMAIN_DESCRIPTORS_BY_URI_CACHE.get(getCacheKey(domainURI, _sharedContainer)); + key = getCacheKey(domainURI, _sharedContainer); + dd = DOMAIN_DESCRIPTORS_BY_URI_CACHE.get(key); + if (null != dd && forUpdate) + DOMAIN_DESCRIPTORS_BY_URI_CACHE.remove(key); + return dd; } /** diff --git a/api/src/org/labkey/api/exp/property/DomainUtil.java b/api/src/org/labkey/api/exp/property/DomainUtil.java index ea78a9f7683..ff00912fda7 100644 --- a/api/src/org/labkey/api/exp/property/DomainUtil.java +++ b/api/src/org/labkey/api/exp/property/DomainUtil.java @@ -751,7 +751,8 @@ public static ValidationException updateDomainDescriptor(GWTDomain> getDomainKinds(); List> getDomainKinds(Container container, User user, Set domainKinds, boolean includeProjectAndShared); diff --git a/assay/api-src/org/labkey/api/assay/plate/PlateService.java b/assay/api-src/org/labkey/api/assay/plate/PlateService.java index 4aa7401735d..711cddabf7c 100644 --- a/assay/api-src/org/labkey/api/assay/plate/PlateService.java +++ b/assay/api-src/org/labkey/api/assay/plate/PlateService.java @@ -252,7 +252,7 @@ static PlateService get() /** * Create the plate metadata domain for this container. */ - @NotNull Domain ensurePlateMetadataDomain(Container container, User user) throws ValidationException; + @NotNull Domain ensurePlateMetadataDomain(Container container, User user, boolean forUpdate) throws ValidationException; /** * Name expressions for plate sets and plates. diff --git a/assay/src/org/labkey/assay/AssayUpgradeCode.java b/assay/src/org/labkey/assay/AssayUpgradeCode.java index 0b7ec76ed08..089b30834c9 100644 --- a/assay/src/org/labkey/assay/AssayUpgradeCode.java +++ b/assay/src/org/labkey/assay/AssayUpgradeCode.java @@ -272,7 +272,7 @@ public static void deletePlateVocabDomains(ModuleContext ctx) throws Exception { // ensure the plate metadata domain for the top level biologics projects if (container.isProject()) - PlateManager.get().ensurePlateMetadataDomain(container, User.getAdminServiceUser()); + PlateManager.get().ensurePlateMetadataDomain(container, User.getAdminServiceUser(), false); biologicsFolders.add(container); } } @@ -535,7 +535,7 @@ public static void renameWellMetadataFields(ModuleContext ctx) throws Exception DbScope scope = AssayDbSchema.getInstance().getSchema().getScope(); for (Container container : metadataContainers) { - Domain domain = PlateManager.get().getPlateMetadataDomain(container, User.getAdminServiceUser()); + Domain domain = PlateManager.get().getPlateMetadataDomain(container, User.getAdminServiceUser(), true); if (domain != null) { try (DbScope.Transaction tx = scope.ensureTransaction()) diff --git a/assay/src/org/labkey/assay/PlateController.java b/assay/src/org/labkey/assay/PlateController.java index c5da7fb4ced..333c17dc567 100644 --- a/assay/src/org/labkey/assay/PlateController.java +++ b/assay/src/org/labkey/assay/PlateController.java @@ -904,7 +904,7 @@ public static class EnsurePlateMetadataDomainAction extends MutatingApiAction> previewFilterCriteriaColumns(@No if (columnNames.isEmpty()) return Collections.emptyMap(); - var replicateDomain = ensurePlateReplicateStatsDomain(container, protocolName); + var replicateDomain = ensurePlateReplicateStatsDomain(container, protocolName, true); var existingFields = getExistingFields(replicateDomain); var columnMap = new HashMap>(); @@ -952,7 +952,7 @@ public void updateReplicateStatsDomain( GWTDomain update ) throws ValidationException { - var replicateDomain = ensurePlateReplicateStatsDomain(protocol); + var replicateDomain = ensurePlateReplicateStatsDomain(protocol, true); var existingReplicateFields = getExistingFields(replicateDomain); var originalFields = new HashMap(); @@ -1085,13 +1085,13 @@ else if (wasValidType) @Override public @Nullable Domain getPlateReplicateStatsDomain(ExpProtocol protocol) { - return getPlateReplicateStatsDomain(protocol.getContainer(), protocol.getName()); + return getPlateReplicateStatsDomain(protocol.getContainer(), protocol.getName(), false); } - private @Nullable Domain getPlateReplicateStatsDomain(Container container, String protocolName) + private @Nullable Domain getPlateReplicateStatsDomain(Container container, String protocolName, boolean forUpdate) { String uri = getPlateReplicateStatsDomainUri(container, protocolName); - return PropertyService.get().getDomain(container, uri); + return PropertyService.get().getDomain(container, uri, forUpdate); } private String getPlateReplicateStatsDomainUri(Container container, String protocolName) @@ -1100,14 +1100,14 @@ private String getPlateReplicateStatsDomainUri(Container container, String proto return domainKind.generateDomainURI(AssaySchema.NAME, protocolName, container, null); } - private @NotNull Domain ensurePlateReplicateStatsDomain(ExpProtocol protocol) + private @NotNull Domain ensurePlateReplicateStatsDomain(ExpProtocol protocol, boolean forUpdate) { - return ensurePlateReplicateStatsDomain(protocol.getContainer(), protocol.getName()); + return ensurePlateReplicateStatsDomain(protocol.getContainer(), protocol.getName(), forUpdate); } - private @NotNull Domain ensurePlateReplicateStatsDomain(Container container, String protocolName) + private @NotNull Domain ensurePlateReplicateStatsDomain(Container container, String protocolName, boolean forUpdate) { - Domain domain = getPlateReplicateStatsDomain(container, protocolName); + Domain domain = getPlateReplicateStatsDomain(container, protocolName, forUpdate); if (domain == null) domain = PropertyService.get().createDomain(container, getPlateReplicateStatsDomainUri(container, protocolName), PlateReplicateStatsDomainKind.NAME); diff --git a/assay/src/org/labkey/assay/plate/PlateManager.java b/assay/src/org/labkey/assay/plate/PlateManager.java index 32a31e8d019..4107b71c644 100644 --- a/assay/src/org/labkey/assay/plate/PlateManager.java +++ b/assay/src/org/labkey/assay/plate/PlateManager.java @@ -172,7 +172,6 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; -import static java.util.Collections.emptySet; import static java.util.Collections.unmodifiableList; import static org.labkey.api.assay.plate.PlateSet.MAX_PLATES; import static org.labkey.api.assay.plate.WellGroup.Type.SAMPLE; @@ -2266,10 +2265,18 @@ public static void deindexPlateSet(Container container, Integer plateSetRowId) * Returns the domain attached to the Well table, */ public @Nullable Domain getPlateMetadataDomain(Container container, User user) + { + return getPlateMetadataDomain(container, user, false); + } + + /** + * Returns the domain attached to the Well table, + */ + public @Nullable Domain getPlateMetadataDomain(Container container, User user, boolean forUpdate) { // the domain is scoped at the project level (project and subfolder scoping) String domainURI = PlateMetadataDomainKind.generateDomainURI(getPlateMetadataDomainContainer(container)); - return PropertyService.get().getDomain(container, domainURI); + return PropertyService.get().getDomain(container, domainURI, forUpdate); } public @Nullable TableInfo getPlateMetadataTable(Container container, User user) @@ -2289,9 +2296,9 @@ public Container getPlateMetadataDomainContainer(Container container) } @Override - public @NotNull Domain ensurePlateMetadataDomain(Container container, User user) throws ValidationException + public @NotNull Domain ensurePlateMetadataDomain(Container container, User user, boolean forUpdate) throws ValidationException { - Domain metadataDomain = getPlateMetadataDomain(container, user); + Domain metadataDomain = getPlateMetadataDomain(container, user, forUpdate); if (metadataDomain == null) { @@ -2311,7 +2318,7 @@ public Container getPlateMetadataDomainContainer(Container container) */ public @NotNull List createPlateMetadataFields(Container container, User user, List fields) throws Exception { - Domain metadataDomain = ensurePlateMetadataDomain(container, user); + Domain metadataDomain = ensurePlateMetadataDomain(container, user, true); DomainKind domainKind = metadataDomain.getDomainKind(); if (!domainKind.canEditDefinition(user, metadataDomain)) @@ -2338,7 +2345,7 @@ public Container getPlateMetadataDomainContainer(Container container) public @NotNull List deletePlateMetadataFields(Container container, User user, List fields) throws Exception { - Domain metadataDomain = getPlateMetadataDomain(container, user); + Domain metadataDomain = getPlateMetadataDomain(container, user, true); if (metadataDomain == null) throw new IllegalArgumentException("Unable to remove fields from the domain, the domain was not found."); diff --git a/assay/src/org/labkey/assay/plate/query/WellTable.java b/assay/src/org/labkey/assay/plate/query/WellTable.java index b081d68fea1..1f6f828b898 100644 --- a/assay/src/org/labkey/assay/plate/query/WellTable.java +++ b/assay/src/org/labkey/assay/plate/query/WellTable.java @@ -355,7 +355,7 @@ public QueryUpdateService getUpdateService() { try { - domain = PlateManager.get().ensurePlateMetadataDomain(container, user); + domain = PlateManager.get().ensurePlateMetadataDomain(container, user, false); } catch (ValidationException e) { diff --git a/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java b/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java index 61c1e5b76f7..5f16d7ae8e0 100644 --- a/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java @@ -128,7 +128,14 @@ public IPropertyType getType(Container container, String typeURI) @Nullable public DomainImpl getDomain(Container container, String domainURI) { - DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainURI, container); + return getDomain(container, domainURI, false); + } + + @Override + @Nullable + public DomainImpl getDomain(Container container, String domainURI, boolean forUpdate) + { + DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainURI, container, forUpdate); if (dd == null) return null; return new DomainImpl(dd); @@ -144,6 +151,16 @@ public Domain getDomain(int domainId) return new DomainImpl(dd); } + @Override + @Nullable + public Domain getDomain(int domainId, boolean forUpdate) + { + DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainId); + if (dd == null) + return null; + return new DomainImpl(dd); + } + @Override @NotNull public Domain createDomain(Container container, String typeURI, String name) From e96be0051dad02ea6d88712202efdd8d5eaa180c Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Thu, 22 May 2025 15:58:43 -0700 Subject: [PATCH 02/17] fewer p's --- api/src/org/labkey/api/data/MutableColumnInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/labkey/api/data/MutableColumnInfo.java b/api/src/org/labkey/api/data/MutableColumnInfo.java index 225a8020ff6..662bbfb697f 100644 --- a/api/src/org/labkey/api/data/MutableColumnInfo.java +++ b/api/src/org/labkey/api/data/MutableColumnInfo.java @@ -97,7 +97,7 @@ default void setSortFieldKeysFromXml(String xml) void setLocked(boolean b); - // return a ColumnInfo that does not suppport MutableColumnInfo or a MutableColumnInfo that is locked + // return a ColumnInfo that does not support MutableColumnInfo or a MutableColumnInfo that is locked default ColumnInfo lock() { setLocked(true); From e9cc42f04135697bcddcd34675ab4de0728667f1 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Thu, 22 May 2025 16:33:59 -0700 Subject: [PATCH 03/17] If not for update, retrieve directly from the database. --- .../org/labkey/api/exp/OntologyManager.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/api/src/org/labkey/api/exp/OntologyManager.java b/api/src/org/labkey/api/exp/OntologyManager.java index c5c1ba75195..2f8e5f75e63 100644 --- a/api/src/org/labkey/api/exp/OntologyManager.java +++ b/api/src/org/labkey/api/exp/OntologyManager.java @@ -2448,10 +2448,10 @@ public static DomainDescriptor getDomainDescriptor(int id) public static DomainDescriptor getDomainDescriptor(int id, boolean forUpdate) { - DomainDescriptor dd = DOMAIN_DESC_BY_ID_CACHE.get(id); if (forUpdate) - DOMAIN_DESC_BY_ID_CACHE.remove(id); - return dd; + return new DomainDescriptorLoader().load(id, null); + + return DOMAIN_DESC_BY_ID_CACHE.get(id); } @Nullable @@ -2466,21 +2466,29 @@ public static DomainDescriptor getDomainDescriptor(String domainURI, Container c if (c == null) return null; + if (forUpdate) + return getDomainDescriptorForUpdate(domainURI, c); + // cache lookup by project. if not found at project level, check to see if global Pair key = getCacheKey(domainURI, c); DomainDescriptor dd = DOMAIN_DESCRIPTORS_BY_URI_CACHE.get(key); if (null != dd) - { - if (forUpdate) - DOMAIN_DESCRIPTORS_BY_URI_CACHE.remove(key); return dd; - } // Try in the /Shared container too key = getCacheKey(domainURI, _sharedContainer); - dd = DOMAIN_DESCRIPTORS_BY_URI_CACHE.get(key); - if (null != dd && forUpdate) - DOMAIN_DESCRIPTORS_BY_URI_CACHE.remove(key); + return DOMAIN_DESCRIPTORS_BY_URI_CACHE.get(key); + } + + @Nullable + private static DomainDescriptor getDomainDescriptorForUpdate(String domainURI, Container c) + { + if (c == null) + return null; + + DomainDescriptor dd = fetchDomainDescriptorFromDB(domainURI, c); + if (dd == null) + dd = fetchDomainDescriptorFromDB(domainURI, _sharedContainer); return dd; } From a5e4c3d26f9e1bcb17203d3bbff55691d9de6c33 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Thu, 22 May 2025 16:34:41 -0700 Subject: [PATCH 04/17] Mark as readOnly if from the cache. --- api/src/org/labkey/api/exp/property/Domain.java | 4 +++- .../experiment/api/property/DomainImpl.java | 15 +++++++++++++++ .../api/property/PropertyServiceImpl.java | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/api/src/org/labkey/api/exp/property/Domain.java b/api/src/org/labkey/api/exp/property/Domain.java index 687bc171add..70589ce7434 100644 --- a/api/src/org/labkey/api/exp/property/Domain.java +++ b/api/src/org/labkey/api/exp/property/Domain.java @@ -75,9 +75,11 @@ public interface Domain extends IPropertyType List getColumns(TableInfo sourceTable, ColumnInfo lsidColumn, Container container, User user); + boolean isReadOnly(); + /* * This returns a lock which will acquire an UPDATE lock on the domain row in the database. - * This can be called at the beginning of a transaction to help reduce the chance of a dead-lock. + * This can be called at the beginning of a transaction to help reduce the chance of a deadlock. * This pattern effectively forces all callers who are trying to manipulate this domain to queue up. */ Lock getDatabaseLock(); diff --git a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java index e4801f6316e..7f39d804482 100644 --- a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java @@ -106,14 +106,21 @@ public class DomainImpl implements Domain private Set _propertyForeignKeys = Collections.emptySet(); private Set _propertyIndices = Collections.emptySet(); private boolean _shouldDeleteAllData = false; + private boolean _isReadOnly = true; // NOTE we could put responsibility for generating column names on the StorageProvisioner // But then we'd have the situation of StorageProvisioner knowing about/updating Domains, which seems fraught transient StorageNameGenerator _storageNameGenerator = null; public DomainImpl(DomainDescriptor dd) + { + this(dd, true); + } + + public DomainImpl(DomainDescriptor dd, boolean isReadOnly) { _dd = dd; + _isReadOnly = isReadOnly; List allFormats = DomainPropertyManager.get().getConditionalFormats(getContainer()); List pds = OntologyManager.getPropertiesForType(getTypeURI(), getContainer()); @@ -206,6 +213,11 @@ public String getLabel(Container container) return ret; } + @Override + public boolean isReadOnly() + { + return _isReadOnly; + } @Override @Nullable // null if not provisioned @@ -543,6 +555,9 @@ public void save(User user, @Nullable String auditComment) throws ChangeProperty public void save(User user, boolean allowAddBaseProperty, boolean saveOnlyIfNotExists, @Nullable String auditComment) throws ChangePropertyDescriptorException { + if (_isReadOnly) + throw new ChangePropertyDescriptorException("Cannot save a domain that is immutable"); + ExperimentService exp = ExperimentService.get(); // NOTE: the synchronization here does not remove the need to add better synchronization in StorageProvisioner, but it helps diff --git a/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java b/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java index 5f16d7ae8e0..c10c39c9592 100644 --- a/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java @@ -138,7 +138,7 @@ public DomainImpl getDomain(Container container, String domainURI, boolean forUp DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainURI, container, forUpdate); if (dd == null) return null; - return new DomainImpl(dd); + return new DomainImpl(dd, !forUpdate); } @Override From 8ef82c9c8642aa7c232e1cfa5e813e55fc3a3d0e Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Fri, 23 May 2025 09:00:11 -0700 Subject: [PATCH 05/17] Get domain for update when ensuring for UsersDomainKind --- core/src/org/labkey/core/query/UsersDomainKind.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/org/labkey/core/query/UsersDomainKind.java b/core/src/org/labkey/core/query/UsersDomainKind.java index 4f6664a46f2..6071fb09b7d 100644 --- a/core/src/org/labkey/core/query/UsersDomainKind.java +++ b/core/src/org/labkey/core/query/UsersDomainKind.java @@ -206,7 +206,7 @@ public static void ensureDomain(ModuleContext context) user = UserManager.getGuestUser(); String domainURI = UsersDomainKind.getDomainURI("core", CoreQuerySchema.USERS_TABLE_NAME, UsersDomainKind.getDomainContainer(), user); - Domain domain = PropertyService.get().getDomain(UsersDomainKind.getDomainContainer(), domainURI); + Domain domain = PropertyService.get().getDomain(UsersDomainKind.getDomainContainer(), domainURI, true); if (domain == null) { From d456974b152b49029710f511ba05df835d88ed9c Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Fri, 23 May 2025 11:48:54 -0700 Subject: [PATCH 06/17] More places to mark domains as for update or not --- .../org/labkey/api/exp/property/Domain.java | 2 +- .../api/reports/model/ReportPropsManager.java | 13 +++-- .../labkey/experiment/ExperimentModule.java | 2 + .../experiment/api/property/DomainImpl.java | 48 +++++++++++++++---- .../api/property/PropertyServiceImpl.java | 17 +++---- .../api/property/StorageProvisionerImpl.java | 4 +- 6 files changed, 58 insertions(+), 28 deletions(-) diff --git a/api/src/org/labkey/api/exp/property/Domain.java b/api/src/org/labkey/api/exp/property/Domain.java index 70589ce7434..18635a1e869 100644 --- a/api/src/org/labkey/api/exp/property/Domain.java +++ b/api/src/org/labkey/api/exp/property/Domain.java @@ -75,7 +75,7 @@ public interface Domain extends IPropertyType List getColumns(TableInfo sourceTable, ColumnInfo lsidColumn, Container container, User user); - boolean isReadOnly(); + boolean isForUpdate(); /* * This returns a lock which will acquire an UPDATE lock on the domain row in the database. diff --git a/api/src/org/labkey/api/reports/model/ReportPropsManager.java b/api/src/org/labkey/api/reports/model/ReportPropsManager.java index cd535d89f19..787487a7dac 100644 --- a/api/src/org/labkey/api/reports/model/ReportPropsManager.java +++ b/api/src/org/labkey/api/reports/model/ReportPropsManager.java @@ -75,7 +75,7 @@ public static ReportPropsManager get() public List getProperties(Container container) { List properties = new ArrayList<>(); - Domain domain = getDomain(container); + Domain domain = getDomain(container, false); if (domain != null) { @@ -91,7 +91,7 @@ public void createProperty(Container container, User user, String name, String l private Map getPropertyMap(Container container) { - Domain domain = getDomain(container); + Domain domain = getDomain(container, false); Map propsMap = new HashMap<>(); if (domain != null) @@ -104,7 +104,7 @@ private Map getPropertyMap(Container container) public synchronized DomainProperty ensureProperty(Container container, User user, String name, String label, PropertyType type) throws ChangePropertyDescriptorException { - Domain domain = getDomain(container); + Domain domain = getDomain(container, false); if (domain != null) { boolean dirty = false; @@ -125,7 +125,10 @@ public synchronized DomainProperty ensureProperty(Container container, User user } if (dirty) + { + domain = getDomain(container, true); domain.save(user); + } return dp; } @@ -184,13 +187,13 @@ public Object getPropertyValue(String entityId, Container container, String prop } @Nullable - private Domain getDomain(Container container) + private Domain getDomain(Container container, boolean forUpdate) { String uri = getDomainURI(container); try (var ignore = SpringActionController.ignoreSqlUpdates()) { DomainDescriptor dd = OntologyManager.ensureDomainDescriptor(uri, PROPERTIES_DOMAIN, container); - return PropertyService.get().getDomain(dd.getDomainId()); + return PropertyService.get().getDomain(dd.getDomainId(), forUpdate); } catch (RuntimeSQLException e) { diff --git a/experiment/src/org/labkey/experiment/ExperimentModule.java b/experiment/src/org/labkey/experiment/ExperimentModule.java index 359e5e14b9e..ccb6e936adb 100644 --- a/experiment/src/org/labkey/experiment/ExperimentModule.java +++ b/experiment/src/org/labkey/experiment/ExperimentModule.java @@ -112,6 +112,7 @@ import org.labkey.experiment.api.ExperimentServiceImpl; import org.labkey.experiment.api.ExperimentStressTest; import org.labkey.experiment.api.GraphAlgorithms; +import org.labkey.experiment.api.property.DomainImpl; import org.labkey.experiment.api.property.StorageNameGenerator; import org.labkey.experiment.lineage.LineagePerfTest; import org.labkey.experiment.api.LineageTest; @@ -942,6 +943,7 @@ public Collection getSummary(Container c) public Set getIntegrationTests() { return Set.of( + DomainImpl.TestCase.class, DomainPropertyImpl.TestCase.class, ExpDataTableImpl.TestCase.class, ExperimentServiceImpl.LineageQueryTestCase.class, diff --git a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java index 7f39d804482..b127c3e6a06 100644 --- a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java @@ -24,6 +24,8 @@ import org.jetbrains.annotations.Nullable; import org.json.JSONArray; import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Test; import org.labkey.api.audit.AuditLogService; import org.labkey.api.audit.AuditTypeEvent; import org.labkey.api.collections.CaseInsensitiveHashMap; @@ -71,11 +73,14 @@ import org.labkey.api.security.User; import org.labkey.api.security.permissions.Permission; import org.labkey.api.settings.AppProps; +import org.labkey.api.test.TestWhen; import org.labkey.api.util.DateUtil; import org.labkey.api.util.GUID; import org.labkey.api.util.JdbcUtil; +import org.labkey.api.util.JunitUtil; import org.labkey.api.util.Pair; import org.labkey.api.util.StringExpressionFactory; +import org.labkey.api.util.TestContext; import org.labkey.api.view.ActionURL; import org.labkey.api.writer.ContainerUser; @@ -106,7 +111,7 @@ public class DomainImpl implements Domain private Set _propertyForeignKeys = Collections.emptySet(); private Set _propertyIndices = Collections.emptySet(); private boolean _shouldDeleteAllData = false; - private boolean _isReadOnly = true; + private boolean _isForUpdate; // NOTE we could put responsibility for generating column names on the StorageProvisioner // But then we'd have the situation of StorageProvisioner knowing about/updating Domains, which seems fraught @@ -114,13 +119,13 @@ public class DomainImpl implements Domain public DomainImpl(DomainDescriptor dd) { - this(dd, true); + this(dd, false); } - public DomainImpl(DomainDescriptor dd, boolean isReadOnly) + public DomainImpl(DomainDescriptor dd, boolean isForUpdate) { _dd = dd; - _isReadOnly = isReadOnly; + _isForUpdate = isForUpdate; List allFormats = DomainPropertyManager.get().getConditionalFormats(getContainer()); List pds = OntologyManager.getPropertiesForType(getTypeURI(), getContainer()); @@ -143,14 +148,15 @@ public DomainImpl(DomainDescriptor dd, boolean isReadOnly) } } - public DomainImpl(Container container, String uri, String name) + public DomainImpl(Container container, String uri, String name, boolean isForUpdate) { - this(container, uri, name, null); + this(container, uri, name, null, isForUpdate); } - public DomainImpl(Container container, String uri, String name, @Nullable TemplateInfo templateInfo) + public DomainImpl(Container container, String uri, String name, @Nullable TemplateInfo templateInfo, boolean isForUpdate) { _new = true; + _isForUpdate = isForUpdate; _dd = new DomainDescriptor.Builder(uri, container) .setName(name) .setTemplateInfoObject(templateInfo) @@ -214,9 +220,9 @@ public String getLabel(Container container) } @Override - public boolean isReadOnly() + public boolean isForUpdate() { - return _isReadOnly; + return _isForUpdate; } @Override @@ -555,7 +561,7 @@ public void save(User user, @Nullable String auditComment) throws ChangeProperty public void save(User user, boolean allowAddBaseProperty, boolean saveOnlyIfNotExists, @Nullable String auditComment) throws ChangePropertyDescriptorException { - if (_isReadOnly) + if (!_isForUpdate) throw new ChangePropertyDescriptorException("Cannot save a domain that is immutable"); ExperimentService exp = ExperimentService.get(); @@ -1540,4 +1546,26 @@ public DomainTemplate getTemplate() { return DomainTemplate.findTemplate(getTemplateInfo(), getDomainKind().getKindName()); } + + @TestWhen(TestWhen.When.BVT) + public static class TestCase extends Assert + { + @Test + public void saveAfterGetReadOnlyDomain() + { + Container c = JunitUtil.getTestContainer(); + String uri = "StorageProvisionImpl/" + GUID.makeGUID(); + DomainImpl d = new DomainImpl(c, uri, "test", false); + User user = TestContext.get().getUser(); + try + { + d.save(user, false); + fail("Save of read-only domain should fail."); + } + catch (ChangePropertyDescriptorException e) + { + // expected exception + } + } + } } diff --git a/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java b/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java index c10c39c9592..434faa91fe6 100644 --- a/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/PropertyServiceImpl.java @@ -138,41 +138,38 @@ public DomainImpl getDomain(Container container, String domainURI, boolean forUp DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainURI, container, forUpdate); if (dd == null) return null; - return new DomainImpl(dd, !forUpdate); + return new DomainImpl(dd, forUpdate); } @Override @Nullable public Domain getDomain(int domainId) { - DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainId); - if (dd == null) - return null; - return new DomainImpl(dd); + return getDomain(domainId, false); } @Override @Nullable public Domain getDomain(int domainId, boolean forUpdate) { - DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainId); + DomainDescriptor dd = OntologyManager.getDomainDescriptor(domainId, forUpdate); if (dd == null) return null; - return new DomainImpl(dd); + return new DomainImpl(dd, forUpdate); } @Override @NotNull public Domain createDomain(Container container, String typeURI, String name) { - return new DomainImpl(container, typeURI, name); + return new DomainImpl(container, typeURI, name, true); } @Override @NotNull public Domain createDomain(Container container, String typeURI, String name, @Nullable TemplateInfo templateInfo) { - return new DomainImpl(container, typeURI, name, templateInfo); + return new DomainImpl(container, typeURI, name, templateInfo, true); } @Override @@ -193,7 +190,7 @@ public Domain createDomain(Container container, String typeURI, String name, @Nu } // return created domain, will only be null in some sort of race condition - domain = PropertyService.get().getDomain(domain.getTypeId()); + domain = PropertyService.get().getDomain(domain.getTypeId(), false); if (null == domain) throw new OptimisticConflictException("Domain deleted: " + domainURI, "", Table.ERROR_DELETED); return domain; diff --git a/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java b/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java index 43fda173531..5a7a810e900 100644 --- a/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java @@ -34,13 +34,13 @@ import org.labkey.api.data.ColumnInfo; import org.labkey.api.data.Container; import org.labkey.api.data.CoreSchema; +import org.labkey.api.data.DatabaseIdentifier; import org.labkey.api.data.DatabaseTableType; import org.labkey.api.data.DbSchema; import org.labkey.api.data.DbSchemaType; import org.labkey.api.data.DbScope; import org.labkey.api.data.DbScope.SchemaTableOptions; import org.labkey.api.data.DbScope.Transaction; -import org.labkey.api.data.DatabaseIdentifier; import org.labkey.api.data.JdbcType; import org.labkey.api.data.MVDisplayColumnFactory; import org.labkey.api.data.ParameterMapStatement; @@ -1806,7 +1806,7 @@ public Set getReservedPropertyNames(Domain domain, User user) DomainImpl d = null; try { - d = new DomainImpl(c, uri, "test") + d = new DomainImpl(c, uri, "test", true) { @Override public DomainKind getDomainKind() From afdab48ea5c1b86bf2b8923366bfff732d5a46fc Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 26 May 2025 07:35:43 -0700 Subject: [PATCH 07/17] Get the mutable domain at the right time --- .../org/labkey/api/reports/model/ReportPropsManager.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/api/src/org/labkey/api/reports/model/ReportPropsManager.java b/api/src/org/labkey/api/reports/model/ReportPropsManager.java index 787487a7dac..dd2033ef5a9 100644 --- a/api/src/org/labkey/api/reports/model/ReportPropsManager.java +++ b/api/src/org/labkey/api/reports/model/ReportPropsManager.java @@ -114,7 +114,8 @@ public synchronized DomainProperty ensureProperty(Container container, User user if (dp == null) { dirty = true; - + // TODO Is there a more efficient way to do this? + domain = getDomain(container, true); DomainProperty prop = domain.addProperty(); prop.setName(name); prop.setLabel(label); @@ -125,10 +126,7 @@ public synchronized DomainProperty ensureProperty(Container container, User user } if (dirty) - { - domain = getDomain(container, true); domain.save(user); - } return dp; } From 48678b56c0bfd5c9009e79d4472d2430a2126a6c Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 26 May 2025 10:21:27 -0700 Subject: [PATCH 08/17] Add forUpdate parameter to more methods --- .../labkey/api/exp/list/ListDefinition.java | 2 + .../labkey/api/exp/property/DomainUtil.java | 1 + .../experiment/api/property/DomainImpl.java | 2 +- .../labkey/list/model/ListDefinitionImpl.java | 14 +++- query/src/org/labkey/query/QueryTestCase.jsp | 2 +- .../org/labkey/study/StudyUnionTableInfo.java | 4 +- .../study/controllers/StudyController.java | 8 +-- .../labkey/study/model/DatasetDefinition.java | 66 +++++++++++-------- .../labkey/study/model/DatasetDomainKind.java | 4 +- .../org/labkey/study/model/StudyManager.java | 17 ++--- .../study/pipeline/DatasetImportRunnable.java | 2 +- .../labkey/study/query/DatasetTableImpl.java | 3 +- .../study/query/DatasetUpdateService.java | 2 +- .../org/labkey/study/view/participantAll.jsp | 2 +- .../study/visitmanager/VisitManager.java | 4 +- 15 files changed, 77 insertions(+), 56 deletions(-) diff --git a/api/src/org/labkey/api/exp/list/ListDefinition.java b/api/src/org/labkey/api/exp/list/ListDefinition.java index 29923d0f2a0..af26042e3d4 100644 --- a/api/src/org/labkey/api/exp/list/ListDefinition.java +++ b/api/src/org/labkey/api/exp/list/ListDefinition.java @@ -277,6 +277,8 @@ public static BodySetting getForValue(int value) Container getContainer(); @Nullable Domain getDomain(); + @Nullable Domain getDomain(boolean forUpdate); + String getName(); String getKeyName(); void setKeyName(String name); diff --git a/api/src/org/labkey/api/exp/property/DomainUtil.java b/api/src/org/labkey/api/exp/property/DomainUtil.java index 836b364c7d3..670400e77b9 100644 --- a/api/src/org/labkey/api/exp/property/DomainUtil.java +++ b/api/src/org/labkey/api/exp/property/DomainUtil.java @@ -689,6 +689,7 @@ public static Domain createDomain(DomainTemplate template, Container container, return createDomain(template.getDomainKind(), template.getDomain(), template.getOptions(), container, user, domainName, template.getTemplateInfo()); } + // TODO add forUpdate parameter public static Domain createDomain( String kindName, GWTDomain domain, diff --git a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java index cdb3685a067..966226fa34e 100644 --- a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java @@ -1551,7 +1551,7 @@ public void saveAfterGetReadOnlyDomain() User user = TestContext.get().getUser(); try { - d.save(user, false); + d.save(user); fail("Save of read-only domain should fail."); } catch (ChangePropertyDescriptorException e) diff --git a/list/src/org/labkey/list/model/ListDefinitionImpl.java b/list/src/org/labkey/list/model/ListDefinitionImpl.java index b89a48084e9..00baff3741a 100644 --- a/list/src/org/labkey/list/model/ListDefinitionImpl.java +++ b/list/src/org/labkey/list/model/ListDefinitionImpl.java @@ -138,13 +138,21 @@ public Container getContainer() @Nullable public Domain getDomain() { + return getDomain(false); + } + + @Override + @Nullable + public Domain getDomain(boolean forUpdate) + { + if (forUpdate) + return PropertyService.get().getDomain(_def.getDomainId(), forUpdate); if (_domain == null) { - _domain = PropertyService.get().getDomain(_def.getDomainId()); + _domain = PropertyService.get().getDomain(_def.getDomainId(), false); } return _domain; } - @Override public String getName() { @@ -391,7 +399,7 @@ public void save(User user, boolean ensureKey, @Nullable Map new if (ensureKey) ensureKey(); - Domain domain = getDomain(); + Domain domain = getDomain(true); if (_new) { diff --git a/query/src/org/labkey/query/QueryTestCase.jsp b/query/src/org/labkey/query/QueryTestCase.jsp index 2001fe6a358..1ff113df5a6 100644 --- a/query/src/org/labkey/query/QueryTestCase.jsp +++ b/query/src/org/labkey/query/QueryTestCase.jsp @@ -1752,7 +1752,7 @@ d,seven,twelve,day,month,date,duration,guid // create a URL expression and MV for suggested columns ListDefinition rDef = ListService.get().getList(c, "R"); - d = rDef.getDomain(); + d = rDef.getDomain(true); d.getPropertyByName("rowid").setURL("https://www.google.com/search?q=${guid}"); d.getPropertyByName("d").setMvEnabled(true); d.getPropertyByName("day").setLookup(new Lookup(d.getContainer(), SchemaKey.fromParts("lists"), "Days$Test")); diff --git a/study/src/org/labkey/study/StudyUnionTableInfo.java b/study/src/org/labkey/study/StudyUnionTableInfo.java index bfed76d8cab..31239578e75 100644 --- a/study/src/org/labkey/study/StudyUnionTableInfo.java +++ b/study/src/org/labkey/study/StudyUnionTableInfo.java @@ -105,7 +105,7 @@ public void init(Collection defs) for (DatasetDefinition def : defs) { - TableInfo ti = def.getStorageTableInfo(); + TableInfo ti = def.getStorageTableInfo(false); if (null == ti || (_user != null && !def.canRead(_user))) continue; count++; @@ -268,7 +268,7 @@ private SQLFragment _getFromSQL(String alias, Set cols, boolean distin SQLFragment sqlf = new SQLFragment(); for (DatasetDefinition def : _defs) { - TableInfo ti = def.getStorageTableInfo(); + TableInfo ti = def.getStorageTableInfo(false); if (null == ti || (_user != null && !def.canRead(_user))) continue; count++; diff --git a/study/src/org/labkey/study/controllers/StudyController.java b/study/src/org/labkey/study/controllers/StudyController.java index 199c228c425..ab4a312eb28 100644 --- a/study/src/org/labkey/study/controllers/StudyController.java +++ b/study/src/org/labkey/study/controllers/StudyController.java @@ -5200,11 +5200,11 @@ private Dataset createDataset(StudySnapshotForm form, BindException errors) thro // def may not be provisioned yet, create before we start adding properties if (def.isQueryDataset()) { - def.provisionQueryDataset(); + def.provisionQueryDataset(true); } else { - def.provisionTable(); + def.provisionTable(true); } Domain d = def.getDomain(); @@ -7122,7 +7122,7 @@ public ApiResponse execute(DefineDatasetForm form, BindException errors) .setStudy(_study) .setDemographicData(false) .setCategoryId(categoryId)); - def.provisionTable(); + def.provisionTable(false); ActionURL redirect = new ActionURL(EditTypeAction.class, getContainer()).addParameter(Dataset.DATASET_KEY, def.getDatasetId()); response.put("redirectUrl", redirect.getLocalURIString()); @@ -7133,7 +7133,7 @@ public ApiResponse execute(DefineDatasetForm form, BindException errors) .setDemographicData(false) .setType(Dataset.TYPE_PLACEHOLDER) .setCategoryId(categoryId)); - def.provisionTable(); + def.provisionTable(false); response.put("datasetId", def.getDatasetId()); break; diff --git a/study/src/org/labkey/study/model/DatasetDefinition.java b/study/src/org/labkey/study/model/DatasetDefinition.java index bab733391ba..722ea7e6d44 100644 --- a/study/src/org/labkey/study/model/DatasetDefinition.java +++ b/study/src/org/labkey/study/model/DatasetDefinition.java @@ -685,7 +685,7 @@ public DatasetSchemaTableInfo getDatasetSchemaTableInfo(User user, boolean check /** why do some datasets have a typeURI, but no domain? */ - private Domain ensureDomain() + private Domain ensureDomain(boolean forUpdate) { assert _lock.isHeldByCurrentThread(); @@ -693,13 +693,13 @@ private Domain ensureDomain() { StudyImpl shared = getDefinitionStudy(); DatasetDefinition ds = shared.getDataset(getDatasetId()); - return null == ds ? null : ds.ensureDomain(); + return null == ds ? null : ds.ensureDomain(forUpdate); } if (null == getTypeURI()) throw new IllegalStateException(); - Domain d = getDomain(); + Domain d = getDomain(forUpdate); if (null != d) return d; @@ -716,7 +716,7 @@ private Domain ensureDomain() } - private TableInfo loadStorageTableInfo() + private TableInfo loadStorageTableInfo(boolean forDomainUpdate) { if (null == getTypeURI()) return null; @@ -725,7 +725,7 @@ private TableInfo loadStorageTableInfo() // consistent order to avoid deadlock try (Transaction t = StudySchema.getInstance().getSchema().getScope().ensureTransaction(_lock)) { - Domain d = ensureDomain(); + Domain d = ensureDomain(forDomainUpdate); // create table may set storageTableName() so uncache _domain if (null == d.getStorageTableName()) @@ -742,28 +742,28 @@ private TableInfo loadStorageTableInfo() /** * just a wrapper for StorageProvisioner.create() */ - public void provisionTable() + public void provisionTable(boolean forDomainUpdate) { try (Transaction t = StudySchema.getInstance().getSchema().getScope().ensureTransaction(_lock)) { - ensureDomainDef(); - loadStorageTableInfo(); + ensureDomainDef(forDomainUpdate); + loadStorageTableInfo(false); StudyManager.getInstance().uncache(this); t.commit(); } } - public void provisionQueryDataset() + public void provisionQueryDataset(boolean forDomainUpdate) { try (Transaction t = StudySchema.getInstance().getSchema().getScope().ensureTransaction(_lock)) { - ensureDomainDef(); + ensureDomainDef(forDomainUpdate); StudyManager.getInstance().uncache(this); t.commit(); } } - private void ensureDomainDef() + private void ensureDomainDef(boolean forUpdate) { _domain = null; if (null == getTypeURI()) @@ -772,11 +772,11 @@ private void ensureDomainDef() d.setTypeURI(DatasetDomainKind.generateDomainURI(getName(), getEntityId(), getContainer())); d.save(null); } - ensureDomain(); + ensureDomain(forUpdate); } @Transient - public TableInfo getStorageTableInfo() throws UnauthorizedException + public TableInfo getStorageTableInfo(boolean forDomainUpdate) throws UnauthorizedException { if (isQueryDataset()) return null; @@ -785,11 +785,11 @@ public TableInfo getStorageTableInfo() throws UnauthorizedException { StudyImpl shared = getDefinitionStudy(); DatasetDefinition ds = shared.getDataset(getDatasetId()); - return null == ds ? null : ds.getStorageTableInfo(); + return null == ds ? null : ds.getStorageTableInfo(forDomainUpdate); } else { - return loadStorageTableInfo(); + return loadStorageTableInfo(forDomainUpdate); } } @@ -808,7 +808,7 @@ public int deleteRows(@Nullable Date cutoff) CPUTimer time = new CPUTimer("purge"); time.start(); - SQLFragment studyDataFrag = new SQLFragment("DELETE FROM ").append(getStorageTableInfo()); + SQLFragment studyDataFrag = new SQLFragment("DELETE FROM ").append(getStorageTableInfo(false)); String and = "\nWHERE "; // only apply a container filter on delete when this is a shared dataset definition @@ -1170,7 +1170,7 @@ public void delete(User user) @Override public void deleteAllRows(User user) { - TableInfo data = getStorageTableInfo(); + TableInfo data = getStorageTableInfo(false); if (null == data) return; DbScope scope = StudySchema.getInstance().getSchema().getScope(); @@ -1416,7 +1416,7 @@ private ColumnInfo getStorageColumn(Domain d, DomainProperty p) } else { - _storage = def.getStorageTableInfo(); + _storage = def.getStorageTableInfo(false); } _template = getTemplateTableInfo(); @@ -1708,7 +1708,7 @@ public CaseInsensitiveHashMap remapSchemaColumns() // shouldn't getStorageTableInfo().getColumn("date").getPropertyURI() == getVisitDateURI()? if (!getStudy().getTimepointType().isVisitBased()) { - m.put(getStorageTableInfo().getColumn("date").getPropertyURI(), getVisitDateURI()); + m.put(getStorageTableInfo(false).getColumn("date").getPropertyURI(), getVisitDateURI()); } return m; @@ -1917,6 +1917,12 @@ public static Set getStandardPropertiesSet() @Override @Transient public Domain getDomain() + { + return getDomain(false); + } + + @Transient + public Domain getDomain(boolean forUpdate) { if (isInherited()) { @@ -1929,22 +1935,26 @@ public Domain getDomain() { if (null == getTypeURI()) return null; - if (null != _domain) + if (null != _domain && !forUpdate) return _domain; } Domain d=null; + // VERIFY: Transaction here is just for synchronization. No updates are happening. try (Transaction t = StudySchema.getInstance().getSchema().getScope().ensureTransaction(_lock)) { - if (null != getTypeURI() && null == _domain) - d = PropertyService.get().getDomain(getContainer(), getTypeURI()); + if (null != getTypeURI() && null == _domain || forUpdate) + d = PropertyService.get().getDomain(getContainer(), getTypeURI(), forUpdate); t.commit(); } synchronized (this) { if (null != d) - _domain = d; + if (forUpdate) // don't stash the for-update domain in the definition + return d; + else + _domain = d; return _domain; } } @@ -2109,7 +2119,7 @@ public void deleteRows(Collection allLSIDs) { List> rowLSIDSlices = slice(allLSIDs); - TableInfo data = getStorageTableInfo(); + TableInfo data = getStorageTableInfo(false); try (Transaction transaction = StudySchema.getInstance().getSchema().getScope().ensureTransaction()) { @@ -2404,7 +2414,7 @@ public DataIteratorBuilder getInsertDataIterator(User user, Container container, * */ public SQLFragment generateLSIDSQL() { - if (null == getStorageTableInfo()) + if (null == getStorageTableInfo(false)) return new SQLFragment("''"); List parts = new ArrayList<>(); @@ -2436,7 +2446,7 @@ public SQLFragment generateLSIDSQL() } else if (getKeyPropertyName() != null) { - var key = getStorageTableInfo().getColumn(getKeyPropertyName()); + var key = getStorageTableInfo(false).getColumn(getKeyPropertyName()); if (null != key) { // It's possible for the key value to be null. In SQL, NULL concatenated with any other value is NULL, @@ -2547,7 +2557,7 @@ private HashMap checkTargetDupesAndDelete(final boolean demogr // duplicate keys found that should be deleted final Set deleteSet = new HashSet<>(); - TableInfo tinfo = getStorageTableInfo(); + TableInfo tinfo = getStorageTableInfo(false); SimpleFilter filter = new SimpleFilter(); filter.addWhereClause((demographic ?"ParticipantId":"LSID") + " IN (" + sbIn + ")", new Object[]{}); if (isShared()) @@ -2604,7 +2614,7 @@ private HashMap checkTargetDupesAndDelete(final boolean demogr */ int getMaxKeyValue() { - TableInfo tInfo = getStorageTableInfo(); + TableInfo tInfo = getStorageTableInfo(false); SQLFragment sqlf = new SQLFragment("SELECT COALESCE(MAX(CAST(_key AS INTEGER)), 0) FROM ").append(tInfo.getFromSQL("_")); Integer newKey = new SqlSelector(tInfo.getSchema(),sqlf).getObject(Integer.class); return newKey.intValue(); diff --git a/study/src/org/labkey/study/model/DatasetDomainKind.java b/study/src/org/labkey/study/model/DatasetDomainKind.java index ba213b65f06..f855a2b7594 100644 --- a/study/src/org/labkey/study/model/DatasetDomainKind.java +++ b/study/src/org/labkey/study/model/DatasetDomainKind.java @@ -195,7 +195,7 @@ public SQLFragment sqlObjectIdsInDomain(Domain domain) DatasetDefinition def = getDatasetDefinition(domain.getTypeURI()); if (null == def) return new SQLFragment("NULL"); - TableInfo ti = def.getStorageTableInfo(); + TableInfo ti = def.getStorageTableInfo(false); SQLFragment sql = new SQLFragment(); sql.append("SELECT O.ObjectId FROM ").append(ti).append(" SD JOIN exp.Object O ON SD.Lsid=O.ObjectURI WHERE O.container=?"); sql.add(def.getContainer()); @@ -494,7 +494,7 @@ else if (!timepointType.isVisitBased() && getKindName().equals(VisitDatasetDomai { List properties = (List)domain.getFields(); - Domain newDomain = def.getDomain(); + Domain newDomain = def.getDomain(true); if (newDomain != null) { Set reservedNames = getReservedPropertyNames(newDomain, user); diff --git a/study/src/org/labkey/study/model/StudyManager.java b/study/src/org/labkey/study/model/StudyManager.java index 6ab7f6b640d..ae50f2837de 100644 --- a/study/src/org/labkey/study/model/StudyManager.java +++ b/study/src/org/labkey/study/model/StudyManager.java @@ -665,7 +665,7 @@ public void createDatasetDefinition(User user, DatasetDefinition datasetDefiniti // This method call has the side effect of ensuring that we have a domain. If we don't create it here, // we're open to a race condition if another thread tries to do something with the dataset's table // and ends up attempting to create the domain as well - datasetDefinition.getStorageTableInfo(); + datasetDefinition.getStorageTableInfo(true); QueryService.get().updateLastModified(); transaction.commit(); @@ -752,7 +752,7 @@ public boolean updateDatasetDefinition(User user, final DatasetDefinition datase if (isProvisioned && isSharedChanged) { // let's not change the shared setting if there are existing rows - if (new TableSelector(datasetDefinition.getStorageTableInfo()).exists()) + if (new TableSelector(datasetDefinition.getStorageTableInfo(false)).exists()) { throw new IllegalArgumentException("Can't change data sharing setting if there are existing data rows."); } @@ -760,7 +760,7 @@ public boolean updateDatasetDefinition(User user, final DatasetDefinition datase if (isProvisioned && isKeyChanged) { - TableInfo storageTableInfo = datasetDefinition.getStorageTableInfo(); + TableInfo storageTableInfo = datasetDefinition.getStorageTableInfo(false); // If so, we need to update the _key column and the LSID @@ -1016,7 +1016,7 @@ private boolean deleteDatasetPropertyOverrides(User user, final DatasetDefinitio public boolean isDataUniquePerParticipant(DatasetDefinition dataset) { // don't use dataset.getTableInfo() since this method is called during updateDatasetDefinition`() and may be in an inconsistent state - TableInfo t = dataset.getStorageTableInfo(); + TableInfo t = dataset.getStorageTableInfo(false); SQLFragment sql = new SQLFragment(); sql.append("SELECT MAX(n) FROM (SELECT COUNT(*) AS n FROM ").append(t.getFromSQL("DS")).append(" GROUP BY ParticipantId) x"); Integer maxCount = new SqlSelector(StudySchema.getInstance().getSchema(), sql).getObject(Integer.class); @@ -1621,7 +1621,7 @@ public void deleteVisits(StudyImpl study, Collection visits, User use { for (DatasetDefinition def : study.getDatasets()) { - TableInfo t = def.getStorageTableInfo(); + TableInfo t = def.getStorageTableInfo(false); if (null == t) continue; @@ -1917,7 +1917,7 @@ public void updateDataQCState(Container container, User user, int datasetId, Col try (Transaction transaction = scope.ensureTransaction()) { // TODO fix updating across study data - SQLFragment sql = new SQLFragment("UPDATE " ).append(def.getStorageTableInfo()); + SQLFragment sql = new SQLFragment("UPDATE " ).append(def.getStorageTableInfo(false)); sql.append(" SET QCState = "); // do string concatenation, rather that using a parameter, for the new state id because Postgres null // parameters are typed which causes a cast exception trying to set the value back to null (bug 6370) @@ -3645,7 +3645,7 @@ public _DatasetDomainChange(Domain domain) private _DatasetDomainChange createDomainChange(String domainURI, String domainName, DatasetDefinitionEntry def, boolean existingDomainsOnly) { _DatasetDomainChange domainChange = new _DatasetDomainChange(); - domainChange.domain = PropertyService.get().getDomain(def.datasetDefinition.getDefinitionContainer(), domainURI); + domainChange.domain = PropertyService.get().getDomain(def.datasetDefinition.getDefinitionContainer(), domainURI, true); if (domainChange.domain == null && existingDomainsOnly) return null; else if (domainChange.domain == null) @@ -3742,7 +3742,8 @@ private void buildPropertySaveAndDeleteLists(Map Domain domain = PropertyService.get().getDomain( datasetDefinitionEntry.datasetDefinition.getDefinitionContainer(), - datasetDefinitionEntry.datasetDefinition.getTypeURI()); + datasetDefinitionEntry.datasetDefinition.getTypeURI(), + true); if (domain != null) domainChangeMap.put(datasetDefinitionEntry.datasetDefinition.getTypeURI(), new _DatasetDomainChange(domain)); } diff --git a/study/src/org/labkey/study/pipeline/DatasetImportRunnable.java b/study/src/org/labkey/study/pipeline/DatasetImportRunnable.java index 5067cabb45c..dfda1b7c774 100644 --- a/study/src/org/labkey/study/pipeline/DatasetImportRunnable.java +++ b/study/src/org/labkey/study/pipeline/DatasetImportRunnable.java @@ -110,7 +110,7 @@ public void validate(List errors) errors.add("Dataset not defined"); else if (_datasetDefinition.getTypeURI() == null) errors.add("Dataset " + (null != _datasetDefinition.getName() ? _datasetDefinition.getName() + ": " : "") + "type is not defined"); - else if (null == _datasetDefinition.getStorageTableInfo()) + else if (null == _datasetDefinition.getStorageTableInfo(false)) errors.add("No database table found for dataset " + _datasetDefinition.getName()); if (_action == AbstractDatasetImportTask.Action.DELETE) diff --git a/study/src/org/labkey/study/query/DatasetTableImpl.java b/study/src/org/labkey/study/query/DatasetTableImpl.java index 74e23885118..1384ccc6426 100644 --- a/study/src/org/labkey/study/query/DatasetTableImpl.java +++ b/study/src/org/labkey/study/query/DatasetTableImpl.java @@ -67,7 +67,6 @@ import org.labkey.api.query.SchemaKey; import org.labkey.api.query.UserIdQueryForeignKey; import org.labkey.api.query.UserSchema; -import org.labkey.api.query.ValidationException; import org.labkey.api.security.User; import org.labkey.api.security.UserPrincipal; import org.labkey.api.security.permissions.DeletePermission; @@ -528,7 +527,7 @@ protected Set getContextualRoles() public Map>> getUniqueIndices() { // Get indices from underlying storage table - Map>> ret = new HashMap<>(wrapTableIndices(getDatasetDefinition().getStorageTableInfo())); + Map>> ret = new HashMap<>(wrapTableIndices(getDatasetDefinition().getStorageTableInfo(false))); String subjectColName = StudyService.get().getSubjectColumnName(getContainer()); // Index enforced in code not on actual database for demographic datasets only diff --git a/study/src/org/labkey/study/query/DatasetUpdateService.java b/study/src/org/labkey/study/query/DatasetUpdateService.java index 653c6854b99..aecc6ca31a5 100644 --- a/study/src/org/labkey/study/query/DatasetUpdateService.java +++ b/study/src/org/labkey/study/query/DatasetUpdateService.java @@ -144,7 +144,7 @@ public enum Config public DatasetUpdateService(DatasetTableImpl table) { - super(table, table.getDatasetDefinition().getStorageTableInfo(), createMVMapping(table.getDatasetDefinition().getDomain())); + super(table, table.getDatasetDefinition().getStorageTableInfo(false), createMVMapping(table.getDatasetDefinition().getDomain())); _dataset = table.getDatasetDefinition(); } diff --git a/study/src/org/labkey/study/view/participantAll.jsp b/study/src/org/labkey/study/view/participantAll.jsp index 1e3f6ad5adb..1477319de67 100644 --- a/study/src/org/labkey/study/view/participantAll.jsp +++ b/study/src/org/labkey/study/view/participantAll.jsp @@ -106,7 +106,7 @@ for (DatasetDefinition def : allDatasets) { - if (!def.isShowByDefault() || null == def.getStorageTableInfo() || def.isDemographicData()) + if (!def.isShowByDefault() || null == def.getStorageTableInfo(false) || def.isDemographicData()) continue; TableInfo t = querySchema.getDatasetTableForLookup(def, null); if (null==t || !t.hasPermission(user, ReadPermission.class)) diff --git a/study/src/org/labkey/study/visitmanager/VisitManager.java b/study/src/org/labkey/study/visitmanager/VisitManager.java index 6e406aaea65..1c11ea19d8a 100644 --- a/study/src/org/labkey/study/visitmanager/VisitManager.java +++ b/study/src/org/labkey/study/visitmanager/VisitManager.java @@ -581,7 +581,7 @@ private static SQLFragment studyDataPtids(Collection defs) TableInfo sti = null; try { - sti = d.getStorageTableInfo(); + sti = d.getStorageTableInfo(false); } catch (IllegalArgumentException x) { @@ -611,7 +611,7 @@ protected void updateStartDates() DatasetDefinition startDateDataset = getStartDateDataset(getStudy()); if (null != startDateDataset) { - TableInfo tInfo = startDateDataset.getStorageTableInfo(); + TableInfo tInfo = startDateDataset.getStorageTableInfo(false); ColumnInfo col = tInfo.getColumn(START_DATE_COLUMN_NAME); Container c = startDateDataset.getContainer(); SQLFragment expr = new SQLFragment() From 68b16187ee37cd33ddcf99c97fd909f501ecea53 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 26 May 2025 11:35:42 -0700 Subject: [PATCH 09/17] Add forUpdate parameter to more methods that are getting domains --- .../api/audit/query/AbstractAuditDomainKind.java | 2 +- api/src/org/labkey/api/data/NameGenerator.java | 14 -------------- .../labkey/api/data/generator/DataGenerator.java | 1 - api/src/org/labkey/api/exp/api/ExpDataClass.java | 2 ++ api/src/org/labkey/api/exp/api/ExpSampleType.java | 3 +++ .../labkey/api/exp/api/SampleTypeDomainKind.java | 5 ++--- .../api/exp/property/AbstractDomainKind.java | 2 +- .../org/labkey/api/exp/property/DomainKind.java | 10 ++++++---- .../org/labkey/api/exp/property/DomainUtil.java | 9 ++++----- .../labkey/api/exp/property/TestDomainKind.java | 2 +- .../issues/AbstractIssuesListDefDomainKind.java | 2 +- .../labkey/api/query/ExtendedTableDomainKind.java | 4 ++-- .../labkey/api/query/SimpleTableDomainKind.java | 2 +- .../org/labkey/api/assay/AssayDomainKind.java | 4 ++-- .../org/labkey/assay/AssayDomainServiceImpl.java | 2 +- .../assay/PlateBasedAssaySampleTypeDomainKind.java | 4 ++-- assay/src/org/labkey/assay/plate/PlateManager.java | 2 +- .../assay/plate/PlateMetadataDomainKind.java | 4 ++-- .../src/org/labkey/core/query/UsersDomainKind.java | 4 ++-- .../labkey/experiment/api/DataClassDomainKind.java | 4 ++-- .../experiment/api/ExpDataClassDataTableImpl.java | 2 +- .../experiment/api/ExpDataClassDataTestCase.jsp | 2 +- .../labkey/experiment/api/ExpDataClassImpl.java | 10 ++++++++-- .../api/ExpProvisionedTableTestHelper.java | 2 +- .../labkey/experiment/api/ExpSampleTypeImpl.java | 11 +++++++++-- .../experiment/api/VocabularyDomainKind.java | 4 ++-- .../controllers/exp/ExperimentController.java | 2 +- .../controllers/property/PropertyController.java | 4 ++-- list/src/org/labkey/list/model/ListDomainKind.java | 6 +++--- .../specimen/model/AbstractSpecimenDomainKind.java | 4 ++-- .../org/labkey/study/model/DatasetDomainKind.java | 4 ++-- .../labkey/survey/query/SurveyTableDomainKind.java | 4 ++-- 32 files changed, 70 insertions(+), 67 deletions(-) diff --git a/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java b/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java index 7daba72dc54..9add67980cd 100644 --- a/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java +++ b/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java @@ -241,7 +241,7 @@ public JSONObject getDomainKindProperties(GWTDomain domain, Container container, } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { throw new UnsupportedOperationException(); } diff --git a/api/src/org/labkey/api/data/NameGenerator.java b/api/src/org/labkey/api/data/NameGenerator.java index 6df428fa11e..bf35e3250c6 100644 --- a/api/src/org/labkey/api/data/NameGenerator.java +++ b/api/src/org/labkey/api/data/NameGenerator.java @@ -15,8 +15,6 @@ */ package org.labkey.api.data; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,17 +24,12 @@ import org.junit.Test; import org.labkey.api.collections.CaseInsensitiveHashMap; import org.labkey.api.collections.CaseInsensitiveHashSet; -import org.labkey.api.exp.Identifiable; -import org.labkey.api.exp.LsidManager; import org.labkey.api.exp.PropertyType; import org.labkey.api.exp.api.ExpData; import org.labkey.api.exp.api.ExpDataClass; -import org.labkey.api.exp.api.ExpLineage; import org.labkey.api.exp.api.ExpLineageOptions; -import org.labkey.api.exp.api.ExpLineageService; import org.labkey.api.exp.api.ExpMaterial; import org.labkey.api.exp.api.ExpObject; -import org.labkey.api.exp.api.ExpRunItem; import org.labkey.api.exp.api.ExpSampleType; import org.labkey.api.exp.api.ExperimentService; import org.labkey.api.exp.api.SampleTypeService; @@ -47,7 +40,6 @@ import org.labkey.api.query.FieldKey; import org.labkey.api.query.QueryKey; import org.labkey.api.query.QueryService; -import org.labkey.api.query.RuntimeValidationException; import org.labkey.api.query.UserSchema; import org.labkey.api.query.ValidationException; import org.labkey.api.reader.TabLoader; @@ -59,12 +51,9 @@ import org.labkey.api.util.StringExpressionFactory; import org.labkey.api.util.StringExpressionFactory.AbstractStringExpression.NullValueBehavior; import org.labkey.api.util.StringExpressionFactory.FieldKeyStringExpression; -import org.labkey.api.util.StringUtilsLabKey; import org.labkey.api.util.SubstitutionFormat; -import org.labkey.api.util.Tuple3; import java.io.IOException; -import java.sql.SQLException; import java.sql.Time; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -73,12 +62,10 @@ import java.util.Calendar; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; @@ -88,7 +75,6 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import static org.labkey.api.data.NameGenerator.NameGenerationExpression.findFirstOpenOrCloseTag; diff --git a/api/src/org/labkey/api/data/generator/DataGenerator.java b/api/src/org/labkey/api/data/generator/DataGenerator.java index d45fd29d5a8..760396cb66d 100644 --- a/api/src/org/labkey/api/data/generator/DataGenerator.java +++ b/api/src/org/labkey/api/data/generator/DataGenerator.java @@ -17,7 +17,6 @@ import org.labkey.api.data.dialect.SqlDialect; import org.labkey.api.dataiterator.DataIteratorBuilder; import org.labkey.api.dataiterator.DetailedAuditLogDataIterator; -import org.labkey.api.dataiterator.ListofMapsDataIterator; import org.labkey.api.dataiterator.MapDataIterator; import org.labkey.api.exp.ExperimentException; import org.labkey.api.exp.api.DataClassDomainKindProperties; diff --git a/api/src/org/labkey/api/exp/api/ExpDataClass.java b/api/src/org/labkey/api/exp/api/ExpDataClass.java index 5d794610259..9af24341dec 100644 --- a/api/src/org/labkey/api/exp/api/ExpDataClass.java +++ b/api/src/org/labkey/api/exp/api/ExpDataClass.java @@ -60,6 +60,8 @@ public interface ExpDataClass extends ExpObject, ExpSearchable Domain getDomain(); + Domain getDomain(boolean forUpdate); + void setDomain(Domain d); String getDescription(); diff --git a/api/src/org/labkey/api/exp/api/ExpSampleType.java b/api/src/org/labkey/api/exp/api/ExpSampleType.java index 547298f64ed..3e746633d00 100644 --- a/api/src/org/labkey/api/exp/api/ExpSampleType.java +++ b/api/src/org/labkey/api/exp/api/ExpSampleType.java @@ -66,6 +66,9 @@ public interface ExpSampleType extends ExpObject, ExpSearchable @NotNull Domain getDomain(); + @NotNull + Domain getDomain(boolean forUpdate); + String getDescription(); /** diff --git a/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java b/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java index 4eab9c0a44b..160160a7c16 100644 --- a/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java +++ b/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java @@ -62,7 +62,6 @@ import org.labkey.api.security.permissions.AdminPermission; import org.labkey.api.security.permissions.DesignSampleTypePermission; import org.labkey.api.util.PageFlowUtil; -import org.labkey.api.util.Pair; import org.labkey.api.util.StringUtilsLabKey; import org.labkey.api.view.ActionURL; import org.labkey.api.view.NotFoundException; @@ -542,7 +541,7 @@ public void validateOptions(Container container, User user, SampleTypeDomainKind } @Override - public Domain createDomain(GWTDomain domain, @Nullable SampleTypeDomainKindProperties arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, @Nullable SampleTypeDomainKindProperties arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { String name = StringUtils.trimToNull(domain.getName()); if (name == null) @@ -602,7 +601,7 @@ public Domain createDomain(GWTDomain domain, @Nullable SampleTypeDomainKindPrope { throw new RuntimeException(e); } - return st.getDomain(); + return st.getDomain(forUpdate); } @Override diff --git a/api/src/org/labkey/api/exp/property/AbstractDomainKind.java b/api/src/org/labkey/api/exp/property/AbstractDomainKind.java index 9b7178a7d56..5966606ecc0 100644 --- a/api/src/org/labkey/api/exp/property/AbstractDomainKind.java +++ b/api/src/org/labkey/api/exp/property/AbstractDomainKind.java @@ -108,7 +108,7 @@ public void deletePropertyDescriptor(Domain domain, User user, PropertyDescripto } @Override - public Domain createDomain(GWTDomain domain, T arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, T arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { return null; } diff --git a/api/src/org/labkey/api/exp/property/DomainKind.java b/api/src/org/labkey/api/exp/property/DomainKind.java index 8b96486c2d5..d6bce31c447 100644 --- a/api/src/org/labkey/api/exp/property/DomainKind.java +++ b/api/src/org/labkey/api/exp/property/DomainKind.java @@ -145,13 +145,15 @@ public Set getReservedPropertyNamePrefixes() /** * Create a Domain appropriate for this DomainKind. - * @param domain The domain design. - * @param options Any domain kind specific properties/options. + * + * @param domain The domain design. + * @param options Any domain kind specific properties/options. * @param container Container - * @param user User + * @param user User + * @param forUpdate Whether the returned domain should be mutable or not * @return The newly created Domain. */ - abstract public Domain createDomain(GWTDomain domain, T options, Container container, User user, @Nullable TemplateInfo templateInfo); + abstract public Domain createDomain(GWTDomain domain, T options, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate); /** * Update a Domain definition appropriate for this DomainKind. diff --git a/api/src/org/labkey/api/exp/property/DomainUtil.java b/api/src/org/labkey/api/exp/property/DomainUtil.java index 670400e77b9..7a02ea816c0 100644 --- a/api/src/org/labkey/api/exp/property/DomainUtil.java +++ b/api/src/org/labkey/api/exp/property/DomainUtil.java @@ -686,10 +686,9 @@ public static GWTPropertyDescriptor getPropertyDescriptor(ColumnType columnXml) public static Domain createDomain(DomainTemplate template, Container container, User user, @Nullable String domainName) throws ValidationException { - return createDomain(template.getDomainKind(), template.getDomain(), template.getOptions(), container, user, domainName, template.getTemplateInfo()); + return createDomain(template.getDomainKind(), template.getDomain(), template.getOptions(), container, user, domainName, template.getTemplateInfo(), false); } - // TODO add forUpdate parameter public static Domain createDomain( String kindName, GWTDomain domain, @@ -697,8 +696,8 @@ public static Domain createDomain( Container container, User user, @Nullable String domainName, - @Nullable TemplateInfo templateInfo - ) throws ValidationException + @Nullable TemplateInfo templateInfo, + boolean forUpdate) throws ValidationException { // Create a copy of the GWTDomain to ensure the template's Domain is not modified domain = new GWTDomain(domain); @@ -735,7 +734,7 @@ public static Domain createDomain( arguments = kind.processArguments(container, user, arguments); Object options = JsonUtil.DEFAULT_MAPPER.convertValue(arguments, kind.getTypeClass()); - Domain created = kind.createDomain(domain, options, container, user, templateInfo); + Domain created = kind.createDomain(domain, options, container, user, templateInfo, forUpdate); if (created == null) throw new RuntimeException("Failed to created domain for kind '" + kind.getKindName() + "' using domain name '" + domainName + "'"); diff --git a/api/src/org/labkey/api/exp/property/TestDomainKind.java b/api/src/org/labkey/api/exp/property/TestDomainKind.java index 47fbf4aeacd..363125723f5 100644 --- a/api/src/org/labkey/api/exp/property/TestDomainKind.java +++ b/api/src/org/labkey/api/exp/property/TestDomainKind.java @@ -165,7 +165,7 @@ public Set getMandatoryPropertyNames(Domain domain) } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { throw new UnsupportedOperationException(); } diff --git a/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java b/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java index 96ff421afb4..d49543e4ea3 100644 --- a/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java +++ b/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java @@ -297,7 +297,7 @@ public Class getTypeClass() } @Override - public Domain createDomain(GWTDomain domain, IssuesDomainKindProperties arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, IssuesDomainKindProperties arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { int issueDefId; try (DbScope.Transaction transaction = ExperimentService.get().getSchema().getScope().ensureTransaction(_lock)) diff --git a/api/src/org/labkey/api/query/ExtendedTableDomainKind.java b/api/src/org/labkey/api/query/ExtendedTableDomainKind.java index 5b91f78925c..902d22a06c7 100644 --- a/api/src/org/labkey/api/query/ExtendedTableDomainKind.java +++ b/api/src/org/labkey/api/query/ExtendedTableDomainKind.java @@ -69,7 +69,7 @@ public Domain updateDomain(Container container, User user, GWTDomain gwtDomain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo) + public Domain createDomain(GWTDomain gwtDomain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo, boolean forUpdate) { if (StringUtils.trimToNull(gwtDomain.getName()) == null) throw new IllegalArgumentException("table name is required"); @@ -113,7 +113,7 @@ public Domain createDomain(GWTDomain gwtDomain, JSONObjec throw new RuntimeException(e); } } - return PropertyService.get().getDomain(container, domainURI); + return PropertyService.get().getDomain(container, domainURI, forUpdate); } @Override diff --git a/api/src/org/labkey/api/query/SimpleTableDomainKind.java b/api/src/org/labkey/api/query/SimpleTableDomainKind.java index 82512ad8680..acd7363beb8 100644 --- a/api/src/org/labkey/api/query/SimpleTableDomainKind.java +++ b/api/src/org/labkey/api/query/SimpleTableDomainKind.java @@ -262,7 +262,7 @@ public String apply(ColumnInfo col) } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo, boolean forUpdate) { String schemaName = (String)arguments.get("schemaName"); String tableName = (String)arguments.get("tableName"); diff --git a/assay/api-src/org/labkey/api/assay/AssayDomainKind.java b/assay/api-src/org/labkey/api/assay/AssayDomainKind.java index d4fc6e37e68..111079ea908 100644 --- a/assay/api-src/org/labkey/api/assay/AssayDomainKind.java +++ b/assay/api-src/org/labkey/api/assay/AssayDomainKind.java @@ -201,13 +201,13 @@ public boolean canCreateDefinition(User user, Container container) } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { DomainDescriptor dd = OntologyManager.ensureDomainDescriptor(domain.getDomainURI(), domain.getName(), container); dd = dd.edit().setDescription(domain.getDescription()).build(); OntologyManager.ensureDomainDescriptor(dd); - return PropertyService.get().getDomain(container, dd.getDomainURI()); + return PropertyService.get().getDomain(container, dd.getDomainURI(), forUpdate); } protected Set getAssayReservedPropertyNames() diff --git a/assay/src/org/labkey/assay/AssayDomainServiceImpl.java b/assay/src/org/labkey/assay/AssayDomainServiceImpl.java index 64eb534d760..eb044936770 100644 --- a/assay/src/org/labkey/assay/AssayDomainServiceImpl.java +++ b/assay/src/org/labkey/assay/AssayDomainServiceImpl.java @@ -450,7 +450,7 @@ public GWTProtocol saveChanges(GWTProtocol assay, boolean replaceIfExisting) thr GWTDomain gwtDomain = DomainUtil.getDomainDescriptor(getUser(), domain.getDomainURI(), getContainer(), true); if (gwtDomain == null) { - Domain newDomain = DomainUtil.createDomain(PropertyService.get().getDomainKind(domain.getDomainURI()).getKindName(), domain, null, getContainer(), getUser(), domain.getName(), null); + Domain newDomain = DomainUtil.createDomain(PropertyService.get().getDomainKind(domain.getDomainURI()).getKindName(), domain, null, getContainer(), getUser(), domain.getName(), null, false); domainURIs.add(newDomain.getTypeURI()); } else diff --git a/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java b/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java index 74b22a0b62f..95e1f781a9b 100644 --- a/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java +++ b/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java @@ -149,10 +149,10 @@ public boolean allowCalculatedFields() } @Override - public Domain createDomain(GWTDomain domain, SampleTypeDomainKindProperties arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, SampleTypeDomainKindProperties arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { JSONObject args = arguments != null ? arguments.toJSONObject() : null; - return _assayDelegate.createDomain(domain, args, container, user, templateInfo); + return _assayDelegate.createDomain(domain, args, container, user, templateInfo, forUpdate); } @NotNull diff --git a/assay/src/org/labkey/assay/plate/PlateManager.java b/assay/src/org/labkey/assay/plate/PlateManager.java index 4107b71c644..20e398b6231 100644 --- a/assay/src/org/labkey/assay/plate/PlateManager.java +++ b/assay/src/org/labkey/assay/plate/PlateManager.java @@ -2308,7 +2308,7 @@ public Container getPlateMetadataDomainContainer(Container container) if (!domainKind.canCreateDefinition(user, domainContainer)) throw new IllegalArgumentException("Unable to create the plate well domain in folder: " + domainContainer.getPath() + "\". Insufficient permissions."); - metadataDomain = DomainUtil.createDomain(PlateMetadataDomainKind.KIND_NAME, new GWTDomain(), null, domainContainer, user, PlateMetadataDomainKind.DOMAiN_NAME, null); + metadataDomain = DomainUtil.createDomain(PlateMetadataDomainKind.KIND_NAME, new GWTDomain(), null, domainContainer, user, PlateMetadataDomainKind.DOMAiN_NAME, null, forUpdate); } return metadataDomain; } diff --git a/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java b/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java index a3e461423a2..956491f2882 100644 --- a/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java +++ b/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java @@ -122,7 +122,7 @@ public Set getMandatoryPropertyNames(Domain domain) } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { try { @@ -131,7 +131,7 @@ public Domain createDomain(GWTDomain domain, JSONObject a ensureDomainProperties(metadataDomain, container); metadataDomain.save(user); - return PropertyService.get().getDomain(container, domainURI); + return PropertyService.get().getDomain(container, domainURI, forUpdate); } catch (Exception e) { diff --git a/core/src/org/labkey/core/query/UsersDomainKind.java b/core/src/org/labkey/core/query/UsersDomainKind.java index 6071fb09b7d..b5fcceed910 100644 --- a/core/src/org/labkey/core/query/UsersDomainKind.java +++ b/core/src/org/labkey/core/query/UsersDomainKind.java @@ -148,9 +148,9 @@ public ActionURL urlShowData(Domain domain, ContainerUser containerUser) } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo, boolean forUpdate) { - return super.createDomain(domain, arguments, getDomainContainer(), user, templateInfo); + return super.createDomain(domain, arguments, getDomainContainer(), user, templateInfo, forUpdate); } @Override diff --git a/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java b/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java index 05e50c23ba0..44c360392ea 100644 --- a/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java +++ b/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java @@ -369,7 +369,7 @@ public void validateOptions(Container container, User user, DataClassDomainKindP } @Override - public Domain createDomain(GWTDomain domain, DataClassDomainKindProperties options, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, DataClassDomainKindProperties options, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { // Issue 45042: Allow for the dataClass description to be set via the create domain API calls if (options.getDescription() == null && domain.getDescription() != null) @@ -387,7 +387,7 @@ public Domain createDomain(GWTDomain domain, DataClassDom templateInfo, domain.getDisabledSystemFields() ); - return dataClass.getDomain(); + return dataClass.getDomain(forUpdate); } catch (ExperimentException e) { diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java index 3b82e7a0953..101c353595f 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java @@ -190,7 +190,7 @@ public ExpDataClassDataTableImpl(String name, UserSchema schema, ContainerFilter @Override public Domain getDomain() { - return _dataClass.getDomain(); + return _dataClass.getDomain(false); } @Override diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp index 07ce3d2914b..312f792438c 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp @@ -982,7 +982,7 @@ public void testViewSupportForVocabularyDomains() throws Exception domain.setDescription(domainDescription); domain.setFields(List.of(prop1)); - Domain lookUpDomain = DomainUtil.createDomain("Vocabulary", domain, null, c, user, domainName, null); + Domain lookUpDomain = DomainUtil.createDomain("Vocabulary", domain, null, c, user, domainName, null, false); Map vocabularyPropertyURIs = helper.getVocabularyPropertyURIS(lookUpDomain); final String locationPropertyURI = vocabularyPropertyURIs.get(locationPropertyName); diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java index abea8c260a8..4e9f65720b3 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java @@ -232,10 +232,16 @@ public long getDataCount(Container c, @Nullable ContainerFilter cf) @Override public Domain getDomain() { + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) + { + if (forUpdate) + return PropertyService.get().getDomain(getContainer(), getLSID(), true); if (_domain == null) - { _domain = PropertyService.get().getDomain(getContainer(), getLSID()); - } return _domain; } diff --git a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java index 699faf27bd2..f1a4fbc64d6 100644 --- a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java +++ b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java @@ -60,7 +60,7 @@ public Domain createVocabularyTestDomain(User user, Container c) throws Validati domain.setDescription(domainDescription); domain.setFields(List.of(prop1, prop2, prop3)); - return DomainUtil.createDomain("Vocabulary", domain, null, c, user, domainName, null); + return DomainUtil.createDomain("Vocabulary", domain, null, c, user, domainName, null, false); } public Map getVocabularyPropertyURIS(Domain domain) diff --git a/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java b/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java index f3f31fc9205..53d6dd5fa2e 100644 --- a/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java @@ -805,9 +805,16 @@ public ExpMaterial getEffectiveSample(Container c, String name, Date effectiveDa @NotNull public Domain getDomain() { - if (_domain == null) + return getDomain(false); + } + + @Override + @NotNull + public Domain getDomain(boolean forUpdate) + { + if (_domain == null || forUpdate) { - _domain = PropertyService.get().getDomain(getContainer(), getLSID()); + _domain = PropertyService.get().getDomain(getContainer(), getLSID(), forUpdate); if (_domain == null) { _domain = PropertyService.get().createDomain(getContainer(), getLSID(), getName()); diff --git a/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java b/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java index a1654378403..ed94f605992 100644 --- a/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java +++ b/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java @@ -144,7 +144,7 @@ public String generateDomainURI(String vocabularyName, Container container) } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { String name = StringUtils.trimToNull(domain.getName()); if (name == null) @@ -174,6 +174,6 @@ public Domain createDomain(GWTDomain domain, JSONObject arguments, Container con throw new RuntimeException(e); } - return PropertyService.get().getDomain(container, domainURI); + return PropertyService.get().getDomain(container, domainURI, forUpdate); } } diff --git a/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java b/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java index 601e1a97e88..ecfa9b3bbaf 100644 --- a/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java +++ b/experiment/src/org/labkey/experiment/controllers/exp/ExperimentController.java @@ -4080,7 +4080,7 @@ protected void deleteObjects(DeleteForm deleteForm) for (ExpSampleType source : sampleTypes) { Domain domain = source.getDomain(); - if (domain != null && !domain.getDomainKind().canDeleteDefinition(getUser(), domain)) + if (!domain.getDomainKind().canDeleteDefinition(getUser(), domain)) { throw new UnauthorizedException(); } diff --git a/experiment/src/org/labkey/experiment/controllers/property/PropertyController.java b/experiment/src/org/labkey/experiment/controllers/property/PropertyController.java index 45a7f993041..d887cd41626 100644 --- a/experiment/src/org/labkey/experiment/controllers/property/PropertyController.java +++ b/experiment/src/org/labkey/experiment/controllers/property/PropertyController.java @@ -317,7 +317,7 @@ public ApiResponse execute(DomainApiForm form, BindException errors) throws Exce } else if (kindName != null) { - domain = DomainUtil.createDomain(kindName, newDomain, form.getOptionsProperties(), getContainer(), getUser(), domainName, null); + domain = DomainUtil.createDomain(kindName, newDomain, form.getOptionsProperties(), getContainer(), getUser(), domainName, null, false); } else { @@ -2147,7 +2147,7 @@ Domain createVocabDomain() throws ValidationException gwtDomain.setFields(gwtProps); - return DomainUtil.createDomain(VocabularyDomainKind.KIND_NAME, gwtDomain, null, c, user, domainName, null); + return DomainUtil.createDomain(VocabularyDomainKind.KIND_NAME, gwtDomain, null, c, user, domainName, null, false); } @Test diff --git a/list/src/org/labkey/list/model/ListDomainKind.java b/list/src/org/labkey/list/model/ListDomainKind.java index 55e67e2ec2d..486ad5952d3 100644 --- a/list/src/org/labkey/list/model/ListDomainKind.java +++ b/list/src/org/labkey/list/model/ListDomainKind.java @@ -360,7 +360,7 @@ public Class getTypeClass() } @Override - public Domain createDomain(GWTDomain domain, ListDomainKindProperties listProperties, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, ListDomainKindProperties listProperties, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { String name = StringUtils.trimToEmpty(domain.getName()); String keyName = listProperties.getKeyName(); @@ -411,7 +411,7 @@ public Domain createDomain(GWTDomain domain, ListDomainKindProperties listProper try (DbScope.Transaction tx = ExperimentService.get().ensureTransaction()) { - Domain d = list.getDomain(); + Domain d = list.getDomain(forUpdate); Set reservedNames = getReservedPropertyNames(d, user); Set lowerReservedNames = reservedNames.stream().map(String::toLowerCase).collect(Collectors.toSet()); @@ -450,7 +450,7 @@ public Domain createDomain(GWTDomain domain, ListDomainKindProperties listProper throw new RuntimeException(e); } - return list.getDomain(); + return list.getDomain(forUpdate); } @Override diff --git a/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java b/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java index a20e2ed1e1a..95e029c206b 100644 --- a/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java @@ -76,7 +76,7 @@ public String getTypeLabel(Domain domain) @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, @Nullable TemplateInfo templateInfo, boolean forUpdate) { ValidationException validation = checkFieldNameLength(domain); if (validation != null) @@ -84,7 +84,7 @@ public Domain createDomain(GWTDomain domain, JSONObject a throw UnexpectedException.wrap(validation); } - return super.createDomain(domain, arguments, container, user, templateInfo); + return super.createDomain(domain, arguments, container, user, templateInfo, forUpdate); } @Override diff --git a/study/src/org/labkey/study/model/DatasetDomainKind.java b/study/src/org/labkey/study/model/DatasetDomainKind.java index f855a2b7594..773d97c175e 100644 --- a/study/src/org/labkey/study/model/DatasetDomainKind.java +++ b/study/src/org/labkey/study/model/DatasetDomainKind.java @@ -399,7 +399,7 @@ public DatasetDomainKindProperties getDomainKindProperties(GWTDomain domain, Con @Override public Domain createDomain(GWTDomain domain, DatasetDomainKindProperties arguments, Container container, User user, - @Nullable TemplateInfo templateInfo) + @Nullable TemplateInfo templateInfo, boolean forUpdate) { arguments.setName(StringUtils.trimToNull(domain.getName())); String name = arguments.getName(); @@ -527,7 +527,7 @@ else if (!timepointType.isVisitBased() && getKindName().equals(VisitDatasetDomai } transaction.commit(); - return study.getDataset(def.getDatasetId()).getDomain(); + return study.getDataset(def.getDatasetId()).getDomain(forUpdate); } catch (Exception e) { diff --git a/survey/src/org/labkey/survey/query/SurveyTableDomainKind.java b/survey/src/org/labkey/survey/query/SurveyTableDomainKind.java index 2f18e4aa006..83bb9a20907 100644 --- a/survey/src/org/labkey/survey/query/SurveyTableDomainKind.java +++ b/survey/src/org/labkey/survey/query/SurveyTableDomainKind.java @@ -62,9 +62,9 @@ public ActionURL urlCreateDefinition(String schemaName, String queryName, Contai } @Override - public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo) + public Domain createDomain(GWTDomain domain, JSONObject arguments, Container container, User user, TemplateInfo templateInfo, boolean forUpdate) { - return super.createDomain(domain, arguments, getDomainContainer(container), user, templateInfo); + return super.createDomain(domain, arguments, getDomainContainer(container), user, templateInfo, forUpdate); } @Override From 00faafe3461753ab3c29763fa69b881aa98e2b8a Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 26 May 2025 13:16:01 -0700 Subject: [PATCH 10/17] get for update --- study/src/org/labkey/study/model/DatasetImportTestCase.jsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/study/src/org/labkey/study/model/DatasetImportTestCase.jsp b/study/src/org/labkey/study/model/DatasetImportTestCase.jsp index 6801849ec80..c6c58c6570c 100644 --- a/study/src/org/labkey/study/model/DatasetImportTestCase.jsp +++ b/study/src/org/labkey/study/model/DatasetImportTestCase.jsp @@ -197,7 +197,7 @@ Dataset createDataset(Study study, String name, DatasetType type) throws Excepti pvLessThan100.setExpressionValue("~lte=100.0"); // define columns - Domain domain = dd.getDomain(); + Domain domain = dd.getDomain(true); DomainProperty measure = domain.addProperty(); measure.setName("Measure"); From d3d31b3a27d1f9f7f97423f89f9557069635e23f Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 26 May 2025 15:37:47 -0700 Subject: [PATCH 11/17] More forUpdate parameters and make methods for data classes and sample types more similar --- .../org/labkey/api/exp/api/ExpDataClass.java | 4 +-- .../api/exp/property/DomainTemplate.java | 2 +- .../labkey/api/exp/property/DomainUtil.java | 7 ++++- .../AbstractIssuesListDefDomainKind.java | 4 +-- .../api/issues/IssuesListDefService.java | 8 ++++-- api/src/org/labkey/api/study/Dataset.java | 2 ++ .../experiment/api/ExpDataClassImpl.java | 28 ++++++++++++------- .../experiment/api/ExpSampleTypeImpl.java | 2 +- .../api/property/StorageProvisionerImpl.java | 12 ++++---- .../org/labkey/issue/model/IssueListDef.java | 7 ++++- .../issue/model/IssuesListDefServiceImpl.java | 4 +-- .../labkey/list/model/ListDefinitionImpl.java | 6 ++-- .../study/assay/StudyPublishManager.java | 2 +- .../labkey/study/model/DatasetDefinition.java | 8 ++---- .../study/query/DatasetUpdateService.java | 2 +- 15 files changed, 58 insertions(+), 40 deletions(-) diff --git a/api/src/org/labkey/api/exp/api/ExpDataClass.java b/api/src/org/labkey/api/exp/api/ExpDataClass.java index 9af24341dec..e785f647e16 100644 --- a/api/src/org/labkey/api/exp/api/ExpDataClass.java +++ b/api/src/org/labkey/api/exp/api/ExpDataClass.java @@ -58,12 +58,12 @@ public interface ExpDataClass extends ExpObject, ExpSearchable void setSampleType(Integer sampleType); + @NotNull Domain getDomain(); + @NotNull Domain getDomain(boolean forUpdate); - void setDomain(Domain d); - String getDescription(); void setDescription(String description); diff --git a/api/src/org/labkey/api/exp/property/DomainTemplate.java b/api/src/org/labkey/api/exp/property/DomainTemplate.java index ce25a89b353..00b965e52b8 100644 --- a/api/src/org/labkey/api/exp/property/DomainTemplate.java +++ b/api/src/org/labkey/api/exp/property/DomainTemplate.java @@ -390,7 +390,7 @@ public Domain createAndImport(Container c, User u, @Nullable String domainName, try (DbScope.Transaction tx = ExperimentService.get().getSchema().getScope().ensureTransaction()) { DomainTemplateGroup.LOG.debug("creating domain '" + domainName + "'"); - d = DomainUtil.createDomain(this, c, u, domainName); + d = DomainUtil.createDomain(this, c, u, domainName, true); tx.commit(); } catch (ValidationException ve) diff --git a/api/src/org/labkey/api/exp/property/DomainUtil.java b/api/src/org/labkey/api/exp/property/DomainUtil.java index 7a02ea816c0..dce5ba484c6 100644 --- a/api/src/org/labkey/api/exp/property/DomainUtil.java +++ b/api/src/org/labkey/api/exp/property/DomainUtil.java @@ -686,7 +686,12 @@ public static GWTPropertyDescriptor getPropertyDescriptor(ColumnType columnXml) public static Domain createDomain(DomainTemplate template, Container container, User user, @Nullable String domainName) throws ValidationException { - return createDomain(template.getDomainKind(), template.getDomain(), template.getOptions(), container, user, domainName, template.getTemplateInfo(), false); + return createDomain(template, container, user, domainName, false); + } + + public static Domain createDomain(DomainTemplate template, Container container, User user, @Nullable String domainName, boolean forUpdate) throws ValidationException + { + return createDomain(template.getDomainKind(), template.getDomain(), template.getOptions(), container, user, domainName, template.getTemplateInfo(), forUpdate); } public static Domain createDomain( diff --git a/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java b/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java index d49543e4ea3..1fe8ba5fc32 100644 --- a/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java +++ b/api/src/org/labkey/api/issues/AbstractIssuesListDefDomainKind.java @@ -318,7 +318,7 @@ public Domain createDomain(GWTDomain domain, IssuesDomainKindProperties argument List properties = (List)domain.getFields(); List indices = (List)domain.getIndices(); - Domain newDomain = IssuesListDefService.get().getDomainFromIssueDefId(issueDefId, container, user); + Domain newDomain = IssuesListDefService.get().getDomainFromIssueDefId(issueDefId, container, user, true); if (newDomain != null) { Set reservedNames = getReservedPropertyNames(newDomain, user); @@ -353,7 +353,7 @@ public Domain createDomain(GWTDomain domain, IssuesDomainKindProperties argument { throw new RuntimeException(e); } - return IssuesListDefService.get().getDomainFromIssueDefId(issueDefId, container, user); + return IssuesListDefService.get().getDomainFromIssueDefId(issueDefId, container, user, forUpdate); } public static void setDefaultValues(Domain domain, Collection requiredProps) diff --git a/api/src/org/labkey/api/issues/IssuesListDefService.java b/api/src/org/labkey/api/issues/IssuesListDefService.java index 1cb66dac38a..af89ad82f03 100644 --- a/api/src/org/labkey/api/issues/IssuesListDefService.java +++ b/api/src/org/labkey/api/issues/IssuesListDefService.java @@ -116,12 +116,14 @@ ValidationException updateIssueDefinition(Container container, User user, GWTDom /** * Get the Domain for a specific issue list definition based on the issue list definition id. + * * @param issueDefId the issue definition row id - * @param container the container to look in - * @param user the user who made the request + * @param container the container to look in + * @param user the user who made the request + * @param forUpdate whether the domain returned should be mutable or not * @return Domain */ - Domain getDomainFromIssueDefId(int issueDefId, Container container, User user); + Domain getDomainFromIssueDefId(int issueDefId, Container container, User user, boolean forUpdate); /** * Register a provider that will add text links to the issue details header link display. diff --git a/api/src/org/labkey/api/study/Dataset.java b/api/src/org/labkey/api/study/Dataset.java index cd13190e51d..4ebb7fa75f8 100644 --- a/api/src/org/labkey/api/study/Dataset.java +++ b/api/src/org/labkey/api/study/Dataset.java @@ -244,6 +244,8 @@ public String getRecallFromStudyAuditMessage(String label, int recordCount) */ @Nullable Domain getDomain(); + @Nullable + Domain getDomain(boolean forUpdate); boolean isShared(); String getName(); diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java index 4e9f65720b3..9bb36190e0f 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java @@ -230,27 +230,35 @@ public long getDataCount(Container c, @Nullable ContainerFilter cf) } @Override + @NotNull public Domain getDomain() { return getDomain(false); } @Override + @NotNull public Domain getDomain(boolean forUpdate) { - if (forUpdate) - return PropertyService.get().getDomain(getContainer(), getLSID(), true); - if (_domain == null) - _domain = PropertyService.get().getDomain(getContainer(), getLSID()); + if (_domain == null || (forUpdate && !_domain.isForUpdate())) + { + _domain = PropertyService.get().getDomain(getContainer(), getLSID(), forUpdate); + if (_domain == null) + { + _domain = PropertyService.get().createDomain(getContainer(), getLSID(), getName()); + try + { + _domain.save(null); + } + catch (ChangePropertyDescriptorException e) + { + throw UnexpectedException.wrap(e); + } + } + } return _domain; } - @Override - public void setDomain(Domain d) - { - _domain = d; - } - @Nullable @Override public ActionURL detailsURL() diff --git a/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java b/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java index 53d6dd5fa2e..0d27c4d59b7 100644 --- a/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java @@ -812,7 +812,7 @@ public Domain getDomain() @NotNull public Domain getDomain(boolean forUpdate) { - if (_domain == null || forUpdate) + if (_domain == null || (forUpdate && !_domain.isForUpdate())) { _domain = PropertyService.get().getDomain(getContainer(), getLSID(), forUpdate); if (_domain == null) diff --git a/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java b/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java index 3ac82a248b8..77f5166736e 100644 --- a/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java @@ -1575,7 +1575,7 @@ public void before() throws Exception domain = PropertyService.get().createDomain(container, lsid.toString(), domainName); domain.save(new User()); StorageProvisioner.createTableInfo(domain); - domain = PropertyService.get().getDomain(domain.getTypeId()); + domain = PropertyService.get().getDomain(domain.getTypeId(), true); } @After @@ -1619,7 +1619,7 @@ public void testRenameProperty() throws Exception propB.setName(newName); domain.save(new User()); - domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId())); + domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId(), true)); Assert.assertNull("renamed column is not present in old name", getJdbcColumnMetadata(domain, oldColumnName)); @@ -1649,7 +1649,7 @@ public void testEnableMv() throws Exception propB.setMvEnabled(true); domain.save(new User()); - domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId())); + domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId(), true)); ColumnInfo col = getJdbcColumnMetadata(domain, propBMvColumnName); Assert.assertNotNull("enabled mvindicator causes mvindicator column to be provisioned", col); @@ -1663,13 +1663,13 @@ public void testDisableMv() throws Exception propB.setMvEnabled(true); domain.save(new User()); - domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId())); + domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId(), true)); propB = domain.getPropertyByName(propNameB); propB.setMvEnabled(false); domain.save(new User()); - domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId())); + domain = Objects.requireNonNull(PropertyService.get().getDomain(domain.getTypeId(), true)); Assert.assertNull("property with disabled mvindicator has no mvindicator column", getJdbcColumnMetadata(domain, propBMvColumnName)); } @@ -1845,7 +1845,7 @@ private void addPropertyB() throws Exception dp.setName(propNameB); domain.save(new User()); - domain = PropertyService.get().getDomain(domain.getTypeId()); + domain = PropertyService.get().getDomain(domain.getTypeId(), true); } private @Nullable ColumnInfo getJdbcColumnMetadata(Domain domain, String columnName) throws Exception diff --git a/issues/src/org/labkey/issue/model/IssueListDef.java b/issues/src/org/labkey/issue/model/IssueListDef.java index c01636fa04b..270f8acff01 100644 --- a/issues/src/org/labkey/issue/model/IssueListDef.java +++ b/issues/src/org/labkey/issue/model/IssueListDef.java @@ -138,9 +138,14 @@ public Container getDomainContainer(User user) } public Domain getDomain(User user) + { + return getDomain(user, false); + } + + public Domain getDomain(User user, boolean forUpdate) { String uri = generateDomainURI(getDomainContainer(user), user, getName(), getKind()); - return PropertyService.get().getDomain(getDomainContainer(user), uri); + return PropertyService.get().getDomain(getDomainContainer(user), uri, forUpdate); } public AbstractIssuesListDefDomainKind getDomainKind() diff --git a/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java b/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java index f05abadefd5..ebdea9d8609 100644 --- a/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java +++ b/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java @@ -234,12 +234,12 @@ public Domain getDomainFromIssueDefName(String issueDefName, Container container } @Override - public Domain getDomainFromIssueDefId(int issueDefId, Container container, User user) + public Domain getDomainFromIssueDefId(int issueDefId, Container container, User user, boolean forUpdate) { IssueListDef issueListDef = IssueManager.getIssueListDef(container, issueDefId); if (issueListDef != null) { - Domain domain = issueListDef.getDomain(user); + Domain domain = issueListDef.getDomain(user, forUpdate); if (domain == null) LOG.warn("Unable to find the domain for issue list definition id: " + issueDefId + " and container: " + container); return domain; diff --git a/list/src/org/labkey/list/model/ListDefinitionImpl.java b/list/src/org/labkey/list/model/ListDefinitionImpl.java index 00baff3741a..f59fa33821b 100644 --- a/list/src/org/labkey/list/model/ListDefinitionImpl.java +++ b/list/src/org/labkey/list/model/ListDefinitionImpl.java @@ -145,11 +145,9 @@ public Domain getDomain() @Nullable public Domain getDomain(boolean forUpdate) { - if (forUpdate) - return PropertyService.get().getDomain(_def.getDomainId(), forUpdate); - if (_domain == null) + if (_domain == null || (forUpdate && !_domain.isForUpdate())) // assure we have a mutable domain if needed, but don't ditch a mutable one because it may not have been saved yet { - _domain = PropertyService.get().getDomain(_def.getDomainId(), false); + _domain = PropertyService.get().getDomain(_def.getDomainId(), forUpdate); } return _domain; } diff --git a/study/src/org/labkey/study/assay/StudyPublishManager.java b/study/src/org/labkey/study/assay/StudyPublishManager.java index cee8e3c4972..a9263c3828e 100644 --- a/study/src/org/labkey/study/assay/StudyPublishManager.java +++ b/study/src/org/labkey/study/assay/StudyPublishManager.java @@ -721,7 +721,7 @@ private Map ensurePropertyDescriptors( User user, DatasetDefinition dataset, List> dataMaps, List types, String keyPropertyName) throws ChangePropertyDescriptorException { - Domain domain = dataset.getDomain(); + Domain domain = dataset.getDomain(true); if (domain == null) { domain = PropertyService.get().createDomain(dataset.getContainer(), dataset.getTypeURI(), dataset.getName()); diff --git a/study/src/org/labkey/study/model/DatasetDefinition.java b/study/src/org/labkey/study/model/DatasetDefinition.java index 722ea7e6d44..e35878664ef 100644 --- a/study/src/org/labkey/study/model/DatasetDefinition.java +++ b/study/src/org/labkey/study/model/DatasetDefinition.java @@ -1921,6 +1921,7 @@ public Domain getDomain() return getDomain(false); } + @Override @Transient public Domain getDomain(boolean forUpdate) { @@ -1935,7 +1936,7 @@ public Domain getDomain(boolean forUpdate) { if (null == getTypeURI()) return null; - if (null != _domain && !forUpdate) + if (null != _domain && (!forUpdate || _domain.isForUpdate())) return _domain; } @@ -1951,10 +1952,7 @@ public Domain getDomain(boolean forUpdate) synchronized (this) { if (null != d) - if (forUpdate) // don't stash the for-update domain in the definition - return d; - else - _domain = d; + _domain = d; return _domain; } } diff --git a/study/src/org/labkey/study/query/DatasetUpdateService.java b/study/src/org/labkey/study/query/DatasetUpdateService.java index aecc6ca31a5..356ea4cce1c 100644 --- a/study/src/org/labkey/study/query/DatasetUpdateService.java +++ b/study/src/org/labkey/study/query/DatasetUpdateService.java @@ -801,7 +801,7 @@ public void updateRowTest() throws Exception dsd = _manager.getDatasetDefinition(_junitStudy, 1001); dsd.refreshDomain(); { - var domain = dsd.getDomain(); + var domain = dsd.getDomain(true); DomainProperty p; p = domain.addProperty(); From 1b03d593f79c9568aad758299b49fac606e944e4 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Tue, 27 May 2025 06:45:05 -0700 Subject: [PATCH 12/17] get mutable domain during import --- .../org/labkey/specimen/SpecimenTableManager.java | 4 ++-- .../specimen/importer/SpecimenSchemaImporter.java | 2 +- .../src/org/labkey/specimen/view/manageSpecimens.jsp | 6 +++--- .../specimen/writer/SpecimenArchiveWriter.java | 2 +- .../labkey/api/specimen/importer/RollupHelper.java | 8 ++++---- .../specimen/model/AbstractSpecimenDomainKind.java | 8 ++++---- .../api/specimen/model/SpecimenDomainKind.java | 4 ++-- .../api/specimen/model/SpecimenEventDomainKind.java | 2 +- .../api/specimen/model/SpecimenTablesProvider.java | 12 ++++++------ .../labkey/api/specimen/model/VialDomainKind.java | 4 ++-- .../org/labkey/study/query/SpecimenDetailTable.java | 4 ++-- .../org/labkey/study/query/SpecimenEventTable.java | 2 +- .../org/labkey/study/query/SpecimenSummaryTable.java | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/specimen/src/org/labkey/specimen/SpecimenTableManager.java b/specimen/src/org/labkey/specimen/SpecimenTableManager.java index 116caa3ac91..1e9f4af2a3c 100644 --- a/specimen/src/org/labkey/specimen/SpecimenTableManager.java +++ b/specimen/src/org/labkey/specimen/SpecimenTableManager.java @@ -139,7 +139,7 @@ private Collection determineSpecimenColumns() SpecimenTablesProvider specimenTablesProvider = new SpecimenTablesProvider(_container, _user, null); - Domain vialDomain = specimenTablesProvider.getDomain("Vial", true); + Domain vialDomain = specimenTablesProvider.getDomain("Vial", true, false); if (null == vialDomain) throw new IllegalStateException("Expected Vial domain to already be created."); @@ -147,7 +147,7 @@ private Collection determineSpecimenColumns() for (DomainProperty domainProperty : vialDomain.getNonBaseProperties()) vialProperties.add(domainProperty.getPropertyDescriptor()); - Domain specimenEventDomain = specimenTablesProvider.getDomain("SpecimenEvent", true); + Domain specimenEventDomain = specimenTablesProvider.getDomain("SpecimenEvent", true, false); if (null == specimenEventDomain) throw new IllegalStateException("Expected SpecimenEvent domain to already be created."); diff --git a/specimen/src/org/labkey/specimen/importer/SpecimenSchemaImporter.java b/specimen/src/org/labkey/specimen/importer/SpecimenSchemaImporter.java index 3b4976725bc..7ace1092f9b 100644 --- a/specimen/src/org/labkey/specimen/importer/SpecimenSchemaImporter.java +++ b/specimen/src/org/labkey/specimen/importer/SpecimenSchemaImporter.java @@ -169,7 +169,7 @@ public void process(SimpleStudyImportContext ctx, VirtualFile studyDir, BindExce final String tableName = tableXml.getTableName(); // get the domain of the table we are updating - final Domain domain = tablesProvider.getDomain(tableName, false); + final Domain domain = tablesProvider.getDomain(tableName, false, true); final Container container = ctx.getContainer(); if (domain != null) diff --git a/specimen/src/org/labkey/specimen/view/manageSpecimens.jsp b/specimen/src/org/labkey/specimen/view/manageSpecimens.jsp index ba2b586feea..3f221e660c1 100644 --- a/specimen/src/org/labkey/specimen/view/manageSpecimens.jsp +++ b/specimen/src/org/labkey/specimen/view/manageSpecimens.jsp @@ -56,9 +56,9 @@ if (!study.hasSourceStudy() && !study.isSnapshotStudy()) { SpecimenTablesProvider stp = new SpecimenTablesProvider(c, user, null); - Domain domainEvent = stp.getDomain("specimenevent",false); - Domain domainVial = stp.getDomain("vial",false); - Domain domainSpecimen = stp.getDomain("specimen",false); + Domain domainEvent = stp.getDomain("specimenevent",false, false); + Domain domainVial = stp.getDomain("vial",false, false); + Domain domainSpecimen = stp.getDomain("specimen",false, false); ActionURL specimenEventUrl = null; ActionURL vialUrl = null; diff --git a/specimen/src/org/labkey/specimen/writer/SpecimenArchiveWriter.java b/specimen/src/org/labkey/specimen/writer/SpecimenArchiveWriter.java index b6775986f61..398784a5f9e 100644 --- a/specimen/src/org/labkey/specimen/writer/SpecimenArchiveWriter.java +++ b/specimen/src/org/labkey/specimen/writer/SpecimenArchiveWriter.java @@ -103,7 +103,7 @@ public void write(Study study, SimpleStudyExportContext ctx, VirtualFile root) t { TableType tableXml = tablesXml.addNewTable(); - Domain domain = tablesProvider.getDomain(entry.getKey(), false); + Domain domain = tablesProvider.getDomain(entry.getKey(), false, false); TableInfo table = entry.getValue(); List columns = new ArrayList<>(); diff --git a/study/api-src/org/labkey/api/specimen/importer/RollupHelper.java b/study/api-src/org/labkey/api/specimen/importer/RollupHelper.java index ae82d66f4b0..b8fac29ad76 100644 --- a/study/api-src/org/labkey/api/specimen/importer/RollupHelper.java +++ b/study/api-src/org/labkey/api/specimen/importer/RollupHelper.java @@ -145,11 +145,11 @@ public static RollupMap getEventToVialRollups(Container contain List rollups = RollupHelper.getEventVialRollups(); SpecimenTablesProvider specimenTablesProvider = new SpecimenTablesProvider(container, user, null); - Domain fromDomain = specimenTablesProvider.getDomain("SpecimenEvent", true); + Domain fromDomain = specimenTablesProvider.getDomain("SpecimenEvent", true, false); if (null == fromDomain) throw new IllegalStateException("Expected SpecimenEvent table to already be created."); - Domain toDomain = specimenTablesProvider.getDomain("Vial", true); + Domain toDomain = specimenTablesProvider.getDomain("Vial", true, false); if (null == toDomain) throw new IllegalStateException("Expected Vial table to already be created."); @@ -175,11 +175,11 @@ public static RollupMap getVialToSpecimenRollups(Container c List rollups = RollupHelper.getVialSpecimenRollups(); SpecimenTablesProvider specimenTablesProvider = new SpecimenTablesProvider(container, user, null); - Domain fromDomain = specimenTablesProvider.getDomain("Vial", true); + Domain fromDomain = specimenTablesProvider.getDomain("Vial", true, false); if (null == fromDomain) throw new IllegalStateException("Expected Vial table to already be created."); - Domain toDomain = specimenTablesProvider.getDomain("Specimen", true); + Domain toDomain = specimenTablesProvider.getDomain("Specimen", true, false); if (null == toDomain) throw new IllegalStateException("Expected Specimen table to already be created."); diff --git a/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java b/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java index 95e029c206b..7ab93f2d336 100644 --- a/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java @@ -190,7 +190,7 @@ protected void setForeignKeyTableInfos(Set forei { if (foreignKey.isProvisioned()) { - Domain domain = provider.getDomain(foreignKey.getTableName(), true); + Domain domain = provider.getDomain(foreignKey.getTableName(), true, false); if (null == domain) throw new IllegalStateException("Expected domain to be created if it didn't already exist."); @@ -218,9 +218,9 @@ protected ValidationException checkRollups( boolean addWarnings) { SpecimenTablesProvider specimenTablesProvider = new SpecimenTablesProvider(container, user, null); - Domain eventDomain = specimenTablesProvider.getDomain("SpecimenEvent", false); - Domain vialDomain = specimenTablesProvider.getDomain("vial", false); - Domain specimenDomain = specimenTablesProvider.getDomain("specimen", false); + Domain eventDomain = specimenTablesProvider.getDomain("SpecimenEvent", false, true); + Domain vialDomain = specimenTablesProvider.getDomain("vial", false, true); + Domain specimenDomain = specimenTablesProvider.getDomain("specimen", false, false); boolean editingSpecimen = null != specimenProps; boolean editingVial = null != vialProps; diff --git a/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java b/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java index b54a91b3ce4..255c67e6411 100644 --- a/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java @@ -175,8 +175,8 @@ public ActionURL urlEditDefinition(Domain domain, ContainerUser containerUser) { exception = new ValidationException(); SpecimenTablesProvider stp = new SpecimenTablesProvider(container, user, null); - Domain domainVial = stp.getDomain("vial", false); - Domain domainSpecimen = stp.getDomain("specimen", false); + Domain domainVial = stp.getDomain("vial", false, false); + Domain domainSpecimen = stp.getDomain("specimen", false, false); // Check for the same name in Specimen and Vial CaseInsensitiveHashSet vialFields = new CaseInsensitiveHashSet(); diff --git a/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java b/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java index f2e341d06ae..81d6f8a96c5 100644 --- a/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java @@ -241,7 +241,7 @@ public ActionURL urlEditDefinition(Domain domain, ContainerUser containerUser) validationException = new ValidationException(); SpecimenTablesProvider stp = new SpecimenTablesProvider(container, user, null); - Domain domainEvent = stp.getDomain("specimenevent", false); + Domain domainEvent = stp.getDomain("specimenevent", false, false); Set mandatoryPropertyNames = getMandatoryPropertyNames(domainEvent); for (GWTPropertyDescriptor prop : update.getFields()) diff --git a/study/api-src/org/labkey/api/specimen/model/SpecimenTablesProvider.java b/study/api-src/org/labkey/api/specimen/model/SpecimenTablesProvider.java index 868dad573d8..5356db474a6 100644 --- a/study/api-src/org/labkey/api/specimen/model/SpecimenTablesProvider.java +++ b/study/api-src/org/labkey/api/specimen/model/SpecimenTablesProvider.java @@ -80,13 +80,13 @@ public SpecimenTablesProvider(Container container, @Nullable User user, @Nullabl } @Nullable - public final Domain getDomain(String tableName, boolean create) + public final Domain getDomain(String tableName, boolean create, boolean forUpdate) { // if the domain doesn't exist and we're asked to create, create it AbstractSpecimenDomainKind domainKind = getDomainKind(tableName); String domainURI = domainKind.generateDomainURI(SCHEMA_NAME, tableName, _container, _user); - Domain ret = PropertyService.get().getDomain(_container, domainURI); + Domain ret = PropertyService.get().getDomain(_container, domainURI, forUpdate); if (null == ret && create) { // Multiple threads attempting to create the domain and provisioned table may result in a constraint @@ -114,7 +114,7 @@ public final Domain getDomain(String tableName, boolean create) domain.save(_user); // Refresh the domain. save() doesn't populate provisioned schema and table names, e.g. - return PropertyService.get().getDomain(_container, domainURI); + return PropertyService.get().getDomain(_container, domainURI, forUpdate); } catch (ChangePropertyDescriptorException e) { @@ -134,7 +134,7 @@ public final Domain getDomain(String tableName, boolean create) @NotNull public TableInfo createTableInfo(String tableName) { - Domain domain = getDomain(tableName, true); + Domain domain = getDomain(tableName, true, false); if (null == domain) throw new IllegalStateException("Unable to create domain for table '" + tableName + "'"); return createTableInfo(domain); @@ -143,7 +143,7 @@ public TableInfo createTableInfo(String tableName) @Nullable public TableInfo getTableInfoIfExists(String tableName) { - Domain domain = getDomain(tableName, false); + Domain domain = getDomain(tableName, false, false); if (null != domain) return createTableInfo(domain); return null; @@ -157,7 +157,7 @@ public void deleteTables() { try { - Domain domain = getDomain(tableName, false); + Domain domain = getDomain(tableName, false, false); if (null != domain) { domain.delete(_user); diff --git a/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java b/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java index 39e311136b1..1d67a539bed 100644 --- a/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java @@ -178,8 +178,8 @@ public ActionURL urlEditDefinition(Domain domain, ContainerUser containerUser) { exception = new ValidationException(); SpecimenTablesProvider stp = new SpecimenTablesProvider(container, user, null); - Domain domainSpecimen = stp.getDomain("specimen", false); - Domain domainVial = stp.getDomain("vial", false); + Domain domainSpecimen = stp.getDomain("specimen", false, false); + Domain domainVial = stp.getDomain("vial", false, false); // Check for the same name in Specimen and Vial CaseInsensitiveHashSet specimenFields = new CaseInsensitiveHashSet(); diff --git a/study/src/org/labkey/study/query/SpecimenDetailTable.java b/study/src/org/labkey/study/query/SpecimenDetailTable.java index 4caa8d5dccc..942aea591e4 100644 --- a/study/src/org/labkey/study/query/SpecimenDetailTable.java +++ b/study/src/org/labkey/study/query/SpecimenDetailTable.java @@ -374,11 +374,11 @@ public static void getOptionalSpecimenAndVialProperties(Container container, Lis List optionalVialProperties) { SpecimenTablesProvider specimenTablesProvider = new SpecimenTablesProvider(container, null, null); - Domain specimenDomain = specimenTablesProvider.getDomain("Specimen", true); + Domain specimenDomain = specimenTablesProvider.getDomain("Specimen", true, false); if (null == specimenDomain) throw new IllegalStateException("Expected Specimen table to already be created."); - Domain vialDomain = specimenTablesProvider.getDomain("Vial", true); + Domain vialDomain = specimenTablesProvider.getDomain("Vial", true, false); if (null == vialDomain) throw new IllegalStateException("Expected Vial table to already be created."); diff --git a/study/src/org/labkey/study/query/SpecimenEventTable.java b/study/src/org/labkey/study/query/SpecimenEventTable.java index 179785eb3bd..0809da6d5bf 100644 --- a/study/src/org/labkey/study/query/SpecimenEventTable.java +++ b/study/src/org/labkey/study/query/SpecimenEventTable.java @@ -80,7 +80,7 @@ public SpecimenEventTable(StudyQuerySchema schema, ContainerFilter cf) // Add optional fields SpecimenTablesProvider specimenTablesProvider = new SpecimenTablesProvider(schema.getContainer(), null, null); - Domain specimenEventDomain = specimenTablesProvider.getDomain("SpecimenEvent", false); + Domain specimenEventDomain = specimenTablesProvider.getDomain("SpecimenEvent", false, false); if (null == specimenEventDomain) throw new IllegalStateException("Expected SpecimenEvent table to already be created."); diff --git a/study/src/org/labkey/study/query/SpecimenSummaryTable.java b/study/src/org/labkey/study/query/SpecimenSummaryTable.java index d07d442de87..3af2d4b529a 100644 --- a/study/src/org/labkey/study/query/SpecimenSummaryTable.java +++ b/study/src/org/labkey/study/query/SpecimenSummaryTable.java @@ -152,7 +152,7 @@ public DisplayColumn createRenderer(ColumnInfo colInfo) addColumn(new ExprColumn(this, "QualityControlFlag", sqlFragConflicts, JdbcType.BOOLEAN)); SpecimenTablesProvider specimenTablesProvider = new SpecimenTablesProvider(schema.getContainer(), null, null); - Domain specimenDomain = specimenTablesProvider.getDomain("Specimen", false); + Domain specimenDomain = specimenTablesProvider.getDomain("Specimen", false, false); if (null == specimenDomain) throw new IllegalStateException("Expected Specimen table to already be created."); addOptionalColumns(specimenDomain.getNonBaseProperties(), false, null); From 4d419068c2bc389c125294bddf2e4a1a31fcddfd Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Tue, 27 May 2025 07:25:01 -0700 Subject: [PATCH 13/17] isForUpdate -> isMutable --- .../org/labkey/api/exp/property/Domain.java | 2 +- .../experiment/api/ExpDataClassImpl.java | 2 +- .../experiment/api/ExpSampleTypeImpl.java | 2 +- .../experiment/api/property/DomainImpl.java | 20 +++++++++---------- .../labkey/list/model/ListDefinitionImpl.java | 2 +- .../labkey/study/model/DatasetDefinition.java | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/api/src/org/labkey/api/exp/property/Domain.java b/api/src/org/labkey/api/exp/property/Domain.java index 0c0255909fd..9ea6c5534f2 100644 --- a/api/src/org/labkey/api/exp/property/Domain.java +++ b/api/src/org/labkey/api/exp/property/Domain.java @@ -76,7 +76,7 @@ public interface Domain extends IPropertyType List getColumns(TableInfo sourceTable, ColumnInfo lsidColumn, Container container, User user); - boolean isForUpdate(); + boolean isMutable(); /* * This returns a lock which will acquire an UPDATE lock on the domain row in the database. diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java index 9bb36190e0f..8cbb9576e45 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java @@ -240,7 +240,7 @@ public Domain getDomain() @NotNull public Domain getDomain(boolean forUpdate) { - if (_domain == null || (forUpdate && !_domain.isForUpdate())) + if (_domain == null || (forUpdate && !_domain.isMutable())) { _domain = PropertyService.get().getDomain(getContainer(), getLSID(), forUpdate); if (_domain == null) diff --git a/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java b/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java index 0d27c4d59b7..10222d086bb 100644 --- a/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java @@ -812,7 +812,7 @@ public Domain getDomain() @NotNull public Domain getDomain(boolean forUpdate) { - if (_domain == null || (forUpdate && !_domain.isForUpdate())) + if (_domain == null || (forUpdate && !_domain.isMutable())) { _domain = PropertyService.get().getDomain(getContainer(), getLSID(), forUpdate); if (_domain == null) diff --git a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java index 966226fa34e..58362a56c14 100644 --- a/experiment/src/org/labkey/experiment/api/property/DomainImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/DomainImpl.java @@ -112,7 +112,7 @@ public class DomainImpl implements Domain private Set _propertyForeignKeys = Collections.emptySet(); private Set _propertyIndices = Collections.emptySet(); private boolean _shouldDeleteAllData = false; - private boolean _isForUpdate; + private final boolean _isMutable; // NOTE we could put responsibility for generating column names on the StorageProvisioner // But then we'd have the situation of StorageProvisioner knowing about/updating Domains, which seems fraught @@ -123,10 +123,10 @@ public DomainImpl(DomainDescriptor dd) this(dd, false); } - public DomainImpl(DomainDescriptor dd, boolean isForUpdate) + public DomainImpl(DomainDescriptor dd, boolean isMutable) { _dd = dd; - _isForUpdate = isForUpdate; + _isMutable = isMutable; List allFormats = DomainPropertyManager.get().getConditionalFormats(getContainer()); List pds = OntologyManager.getPropertiesForType(getTypeURI(), getContainer()); @@ -149,15 +149,15 @@ public DomainImpl(DomainDescriptor dd, boolean isForUpdate) } } - public DomainImpl(Container container, String uri, String name, boolean isForUpdate) + public DomainImpl(Container container, String uri, String name, boolean isMutable) { - this(container, uri, name, null, isForUpdate); + this(container, uri, name, null, isMutable); } - public DomainImpl(Container container, String uri, String name, @Nullable TemplateInfo templateInfo, boolean isForUpdate) + public DomainImpl(Container container, String uri, String name, @Nullable TemplateInfo templateInfo, boolean isMutable) { _new = true; - _isForUpdate = isForUpdate; + _isMutable = isMutable; _dd = new DomainDescriptor.Builder(uri, container) .setName(name) .setTemplateInfoObject(templateInfo) @@ -221,9 +221,9 @@ public String getLabel(Container container) } @Override - public boolean isForUpdate() + public boolean isMutable() { - return _isForUpdate; + return _isMutable; } @Override @@ -566,7 +566,7 @@ public void save(User user, boolean allowAddBaseProperty, boolean saveOnlyIfNotE @Nullable Map oldRecordMap, @Nullable Map newRecordMap, @Nullable List oldCalculatedFields, @Nullable List newCalculatedFields) throws ChangePropertyDescriptorException { - if (!_isForUpdate) + if (!_isMutable) throw new ChangePropertyDescriptorException("Cannot save a domain that is immutable"); ExperimentService exp = ExperimentService.get(); diff --git a/list/src/org/labkey/list/model/ListDefinitionImpl.java b/list/src/org/labkey/list/model/ListDefinitionImpl.java index f59fa33821b..9ca3cef6a67 100644 --- a/list/src/org/labkey/list/model/ListDefinitionImpl.java +++ b/list/src/org/labkey/list/model/ListDefinitionImpl.java @@ -145,7 +145,7 @@ public Domain getDomain() @Nullable public Domain getDomain(boolean forUpdate) { - if (_domain == null || (forUpdate && !_domain.isForUpdate())) // assure we have a mutable domain if needed, but don't ditch a mutable one because it may not have been saved yet + if (_domain == null || (forUpdate && !_domain.isMutable())) // assure we have a mutable domain if needed, but don't ditch a mutable one because it may not have been saved yet { _domain = PropertyService.get().getDomain(_def.getDomainId(), forUpdate); } diff --git a/study/src/org/labkey/study/model/DatasetDefinition.java b/study/src/org/labkey/study/model/DatasetDefinition.java index e35878664ef..8920863bdbe 100644 --- a/study/src/org/labkey/study/model/DatasetDefinition.java +++ b/study/src/org/labkey/study/model/DatasetDefinition.java @@ -1936,7 +1936,7 @@ public Domain getDomain(boolean forUpdate) { if (null == getTypeURI()) return null; - if (null != _domain && (!forUpdate || _domain.isForUpdate())) + if (null != _domain && (!forUpdate || _domain.isMutable())) return _domain; } From 3519d5885453d1f62b359ed9735783e8ada9e6da Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 28 May 2025 10:42:37 -0700 Subject: [PATCH 14/17] Still more forUpdate parameters --- .../api/assay/AbstractAssayProvider.java | 35 ++++++++++++++----- .../assay/AbstractAssayTsvDataHandler.java | 2 +- .../org/labkey/api/assay/AssayProvider.java | 6 ++++ .../api/audit/AbstractAuditTypeProvider.java | 5 +-- .../labkey/api/audit/AuditTypeProvider.java | 2 ++ .../audit/query/DefaultAuditTypeTable.java | 9 ++++- .../labkey/api/data/AbstractTableInfo.java | 7 ++++ .../org/labkey/api/data/SchemaTableInfo.java | 7 ++++ api/src/org/labkey/api/data/TableInfo.java | 6 ++++ .../api/issues/IssuesListDefService.java | 8 +++-- .../labkey/api/query/SimpleUserSchema.java | 10 ++++-- .../api/reports/model/ReportPropsManager.java | 2 +- .../AbstractDilutionAssayProvider.java | 2 +- .../AbstractPlateBasedAssayProvider.java | 2 +- .../org/labkey/assay/AssayUpgradeCode.java | 4 +-- .../plate/AssayPlateMetadataServiceImpl.java | 12 +++---- .../assay/plate/AssayPlateTriggerFactory.java | 2 +- .../src/org/labkey/core/query/UsersTable.java | 8 ++++- .../api/ExpDataClassDataTableImpl.java | 8 ++++- .../experiment/api/ExpMaterialTableImpl.java | 9 ++++- .../issue/model/IssuesListDefServiceImpl.java | 4 +-- .../org/labkey/issue/query/IssuesTable.java | 9 ++++- .../org/labkey/list/model/ListImporter.java | 4 +-- list/src/org/labkey/list/model/ListTable.java | 8 ++++- .../study/controllers/StudyController.java | 2 +- .../dataset/DatasetSnapshotProvider.java | 2 +- .../importer/DefaultStudyDesignImporter.java | 3 +- .../labkey/study/model/DatasetDefinition.java | 8 ++++- .../org/labkey/study/query/CohortTable.java | 11 ++++++ .../labkey/study/query/DatasetTableImpl.java | 8 ++++- .../study/query/StudyPropertiesTable.java | 12 +++++++ .../org/labkey/survey/query/SurveysTable.java | 8 ++++- 32 files changed, 180 insertions(+), 45 deletions(-) diff --git a/api/src/org/labkey/api/assay/AbstractAssayProvider.java b/api/src/org/labkey/api/assay/AbstractAssayProvider.java index a4bf95f51c7..5188ab4b1cc 100644 --- a/api/src/org/labkey/api/assay/AbstractAssayProvider.java +++ b/api/src/org/labkey/api/assay/AbstractAssayProvider.java @@ -74,7 +74,6 @@ import org.labkey.api.exp.api.IAssayDomainType; import org.labkey.api.exp.property.Domain; import org.labkey.api.exp.property.DomainProperty; -import org.labkey.api.exp.property.DomainUtil; import org.labkey.api.exp.property.PropertyService; import org.labkey.api.exp.query.ExpRunTable; import org.labkey.api.files.FileContentService; @@ -383,31 +382,37 @@ public static String getDomainURIForPrefixIfExists(ExpProtocol protocol, String return result; } - public static Domain getDomainByPrefix(ExpProtocol protocol, String domainPrefix) + public static Domain getDomainByPrefix(ExpProtocol protocol, String domainPrefix, boolean forUpdate) { Container container = protocol.getContainer(); - return PropertyService.get().getDomain(container, getDomainURIForPrefix(protocol, domainPrefix)); + return PropertyService.get().getDomain(container, getDomainURIForPrefix(protocol, domainPrefix), forUpdate); } @Nullable - public static Domain getDomainByPrefixIfExists(ExpProtocol protocol, String domainPrefix) + public static Domain getDomainByPrefixIfExists(ExpProtocol protocol, String domainPrefix, boolean forUpdate) { String domainURI = getDomainURIForPrefixIfExists(protocol, domainPrefix); if (null == domainURI) return null; Container container = protocol.getContainer(); - return PropertyService.get().getDomain(container, domainURI); + return PropertyService.get().getDomain(container, domainURI, forUpdate); } @Override public Domain getResultsDomain(ExpProtocol protocol) { - return getDomainByPrefix(protocol, ExpProtocol.ASSAY_DOMAIN_DATA); + return getResultsDomain(protocol, false); + } + + @Override + public Domain getResultsDomain(ExpProtocol protocol, boolean forUpdate) + { + return getDomainByPrefix(protocol, ExpProtocol.ASSAY_DOMAIN_DATA, forUpdate); } protected @Nullable Domain getResultsDomainIfExists(ExpProtocol protocol) { - return getDomainByPrefixIfExists(protocol, ExpProtocol.ASSAY_DOMAIN_DATA); + return getDomainByPrefixIfExists(protocol, ExpProtocol.ASSAY_DOMAIN_DATA, false); } @Override @@ -423,13 +428,25 @@ public void afterDomainChange(User user, ExpProtocol protocol, GWTDomain dataMap, Collection types) diff --git a/api/src/org/labkey/api/assay/AbstractAssayTsvDataHandler.java b/api/src/org/labkey/api/assay/AbstractAssayTsvDataHandler.java index d111fb55845..7d394df7c14 100644 --- a/api/src/org/labkey/api/assay/AbstractAssayTsvDataHandler.java +++ b/api/src/org/labkey/api/assay/AbstractAssayTsvDataHandler.java @@ -395,7 +395,7 @@ public void beforeDeleteData(List data, User user) throws ExperimentExc // results/data domain for TSV-style assays try { - domain = AbstractAssayProvider.getDomainByPrefixIfExists(protocol, ExpProtocol.ASSAY_DOMAIN_DATA) ; + domain = AbstractAssayProvider.getDomainByPrefixIfExists(protocol, ExpProtocol.ASSAY_DOMAIN_DATA, false) ; } catch (IllegalStateException ignored) { diff --git a/api/src/org/labkey/api/assay/AssayProvider.java b/api/src/org/labkey/api/assay/AssayProvider.java index 925d74281ca..5232baba43b 100644 --- a/api/src/org/labkey/api/assay/AssayProvider.java +++ b/api/src/org/labkey/api/assay/AssayProvider.java @@ -99,10 +99,16 @@ enum ReRunSupport Domain getBatchDomain(ExpProtocol protocol); + Domain getBatchDomain(ExpProtocol protocol, boolean forUpdate); + Domain getRunDomain(ExpProtocol protocol); + Domain getRunDomain(ExpProtocol protocol, boolean forUpdate); + Domain getResultsDomain(ExpProtocol protocol); + Domain getResultsDomain(ExpProtocol protocol, boolean forUpdate); + void beforeDomainChange(User user, ExpProtocol protocol, GWTDomain orig, GWTDomain update) throws ValidationException; void afterDomainChange(User user, ExpProtocol protocol, GWTDomain orig, GWTDomain update) throws ValidationException; diff --git a/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java b/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java index ae47f9de747..851a7d1b386 100644 --- a/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java +++ b/api/src/org/labkey/api/audit/AbstractAuditTypeProvider.java @@ -138,7 +138,7 @@ public void initializeProvider(User user) domain.addPropertyOfPropertyDescriptor(pd); } domain.save(user); - domain = getDomain(); + domain = getDomain(true); } catch (ChangePropertyDescriptorException e) { @@ -303,7 +303,8 @@ public final Domain getDomain() return getDomain(false); } - protected Domain getDomain(boolean forUpdate) + @Override + public final Domain getDomain(boolean forUpdate) { DomainKind domainKind = getDomainKind(); diff --git a/api/src/org/labkey/api/audit/AuditTypeProvider.java b/api/src/org/labkey/api/audit/AuditTypeProvider.java index 81f1d8e9ccd..332f1a5d681 100644 --- a/api/src/org/labkey/api/audit/AuditTypeProvider.java +++ b/api/src/org/labkey/api/audit/AuditTypeProvider.java @@ -44,6 +44,8 @@ public interface AuditTypeProvider Domain getDomain(); + Domain getDomain(boolean forUpdate); + TableInfo createTableInfo(UserSchema schema, ContainerFilter cf); Class getEventClass(); diff --git a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java index fc3d4a5441c..61e7497a9f0 100644 --- a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java +++ b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java @@ -142,7 +142,14 @@ protected void initColumn(MutableColumnInfo col) @Override public Domain getDomain() { - return _provider.getDomain(); + return getDomain(false); + } + + @Nullable + @Override + public Domain getDomain(boolean forUpdate) + { + return _provider.getDomain(forUpdate); } @Nullable diff --git a/api/src/org/labkey/api/data/AbstractTableInfo.java b/api/src/org/labkey/api/data/AbstractTableInfo.java index 79aa2ef871f..e8eca0662bd 100644 --- a/api/src/org/labkey/api/data/AbstractTableInfo.java +++ b/api/src/org/labkey/api/data/AbstractTableInfo.java @@ -1769,6 +1769,13 @@ public Domain getDomain() return null; } + @Nullable + @Override + public Domain getDomain(boolean forUpdate) + { + return getDomain(); + } + @Nullable @Override public DomainKind getDomainKind() diff --git a/api/src/org/labkey/api/data/SchemaTableInfo.java b/api/src/org/labkey/api/data/SchemaTableInfo.java index 1fecb0c4d66..3ff1f3fa94a 100644 --- a/api/src/org/labkey/api/data/SchemaTableInfo.java +++ b/api/src/org/labkey/api/data/SchemaTableInfo.java @@ -857,6 +857,13 @@ public Domain getDomain() return null; } + @Nullable + @Override + public Domain getDomain(boolean forUpdate) + { + return getDomain(); + } + @Nullable @Override public DomainKind getDomainKind() diff --git a/api/src/org/labkey/api/data/TableInfo.java b/api/src/org/labkey/api/data/TableInfo.java index ea6450d0a1a..d396f31d651 100644 --- a/api/src/org/labkey/api/data/TableInfo.java +++ b/api/src/org/labkey/api/data/TableInfo.java @@ -445,6 +445,12 @@ default List> getValidatedImportTemplates(ViewContext ctx) @Nullable Domain getDomain(); + /** + * Get Domain associated with this TableInfo if any. + */ + @Nullable + Domain getDomain(boolean forUpdate); + /** * Get DomainKind associated with this TableInfo if any. * Domain may or may not exist even if DomainKind is available. diff --git a/api/src/org/labkey/api/issues/IssuesListDefService.java b/api/src/org/labkey/api/issues/IssuesListDefService.java index af89ad82f03..d3f420d0cfc 100644 --- a/api/src/org/labkey/api/issues/IssuesListDefService.java +++ b/api/src/org/labkey/api/issues/IssuesListDefService.java @@ -107,12 +107,14 @@ ValidationException updateIssueDefinition(Container container, User user, GWTDom /** * Get the Domain for a specific issue list definition based on the issue list definition name. + * * @param issueDefName the name of the issue list definition to look for - * @param container the container to look in - * @param user the user who made the request + * @param container the container to look in + * @param user the user who made the request + * @param forUpdate whether the domain returned should be mutable or not * @return Domain */ - Domain getDomainFromIssueDefName(String issueDefName, Container container, User user); + Domain getDomainFromIssueDefName(String issueDefName, Container container, User user, boolean forUpdate); /** * Get the Domain for a specific issue list definition based on the issue list definition id. diff --git a/api/src/org/labkey/api/query/SimpleUserSchema.java b/api/src/org/labkey/api/query/SimpleUserSchema.java index 9dc3023953b..d7f7bf720f7 100644 --- a/api/src/org/labkey/api/query/SimpleUserSchema.java +++ b/api/src/org/labkey/api/query/SimpleUserSchema.java @@ -457,14 +457,20 @@ protected Container getDomainContainer() @Override public Domain getDomain() + { + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) { if (_objectUriCol == null) return null; - if (_domain == null) + if (_domain == null || (forUpdate && !_domain.isMutable())) { String domainURI = getDomainURI(); - _domain = PropertyService.get().getDomain(getDomainContainer(), domainURI); + _domain = PropertyService.get().getDomain(getDomainContainer(), domainURI, forUpdate); } return _domain; diff --git a/api/src/org/labkey/api/reports/model/ReportPropsManager.java b/api/src/org/labkey/api/reports/model/ReportPropsManager.java index dd2033ef5a9..5320a2b9a74 100644 --- a/api/src/org/labkey/api/reports/model/ReportPropsManager.java +++ b/api/src/org/labkey/api/reports/model/ReportPropsManager.java @@ -114,7 +114,7 @@ public synchronized DomainProperty ensureProperty(Container container, User user if (dp == null) { dirty = true; - // TODO Is there a more efficient way to do this? + // Get a mutable version of the domain. domain = getDomain(container, true); DomainProperty prop = domain.addProperty(); prop.setName(name); diff --git a/assay/api-src/org/labkey/api/assay/dilution/AbstractDilutionAssayProvider.java b/assay/api-src/org/labkey/api/assay/dilution/AbstractDilutionAssayProvider.java index 885cdee8c1a..6171b374f78 100644 --- a/assay/api-src/org/labkey/api/assay/dilution/AbstractDilutionAssayProvider.java +++ b/assay/api-src/org/labkey/api/assay/dilution/AbstractDilutionAssayProvider.java @@ -135,7 +135,7 @@ protected Map> getRequiredDomainProperties() } @Override - public Domain getResultsDomain(ExpProtocol protocol) + public Domain getResultsDomain(ExpProtocol protocol, boolean forUpdate) { return null; } diff --git a/assay/api-src/org/labkey/api/assay/plate/AbstractPlateBasedAssayProvider.java b/assay/api-src/org/labkey/api/assay/plate/AbstractPlateBasedAssayProvider.java index 25f7628965f..17d2bbc2a87 100644 --- a/assay/api-src/org/labkey/api/assay/plate/AbstractPlateBasedAssayProvider.java +++ b/assay/api-src/org/labkey/api/assay/plate/AbstractPlateBasedAssayProvider.java @@ -159,7 +159,7 @@ public File getSampleMetadataFile(Container container, int runId) @Override public Domain getSampleWellGroupDomain(ExpProtocol protocol) { - return getDomainByPrefix(protocol, ASSAY_DOMAIN_SAMPLE_WELLGROUP); + return getDomainByPrefix(protocol, ASSAY_DOMAIN_SAMPLE_WELLGROUP, false); } @Override diff --git a/assay/src/org/labkey/assay/AssayUpgradeCode.java b/assay/src/org/labkey/assay/AssayUpgradeCode.java index 089b30834c9..093e9c822d2 100644 --- a/assay/src/org/labkey/assay/AssayUpgradeCode.java +++ b/assay/src/org/labkey/assay/AssayUpgradeCode.java @@ -751,7 +751,7 @@ public static void initializeWellExclusions(ModuleContext ctx) throws Exception if (provider.isPlateMetadataEnabled(protocol)) { // ensure the QC state column exists in the result domain - Domain resultDomain = provider.getResultsDomain(protocol); + Domain resultDomain = provider.getResultsDomain(protocol, true); if (resultDomain.getPropertyByName(AssayResultDomainKind.Column.State.name()) == null) { _log.info(String.format("Adding the %s field to the results domain for assay : %s", AssayResultDomainKind.Column.State.name(), protocol.getName())); @@ -796,7 +796,7 @@ public static void initializeHitSelectionCriteria(ModuleContext ctx) throws Exce if (provider != null && provider.isPlateMetadataEnabled(protocol)) { // ensure the QC state column exists in the result domain - Domain runDomain = provider.getRunDomain(protocol); + Domain runDomain = provider.getRunDomain(protocol, true); if (runDomain != null && runDomain.getPropertyByName(HIT_SELECTION_CRITERIA_COLUMN_NAME) == null) { _log.info("Adding the \"{}\" field to the run domain for assay : {}", HIT_SELECTION_CRITERIA_COLUMN_NAME, protocol.getName()); diff --git a/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java b/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java index 2edcb366be5..dfd3b15cc89 100644 --- a/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java +++ b/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java @@ -913,7 +913,7 @@ public Map> previewFilterCriteriaColumns(@No if (columnNames.isEmpty()) return Collections.emptyMap(); - var replicateDomain = ensurePlateReplicateStatsDomain(container, protocolName, true); + var replicateDomain = ensurePlateReplicateStatsDomain(container, protocolName); var existingFields = getExistingFields(replicateDomain); var columnMap = new HashMap>(); @@ -952,7 +952,7 @@ public void updateReplicateStatsDomain( GWTDomain update ) throws ValidationException { - var replicateDomain = ensurePlateReplicateStatsDomain(protocol, true); + var replicateDomain = ensurePlateReplicateStatsDomain(protocol); var existingReplicateFields = getExistingFields(replicateDomain); var originalFields = new HashMap(); @@ -1100,14 +1100,14 @@ private String getPlateReplicateStatsDomainUri(Container container, String proto return domainKind.generateDomainURI(AssaySchema.NAME, protocolName, container, null); } - private @NotNull Domain ensurePlateReplicateStatsDomain(ExpProtocol protocol, boolean forUpdate) + private @NotNull Domain ensurePlateReplicateStatsDomain(ExpProtocol protocol) { - return ensurePlateReplicateStatsDomain(protocol.getContainer(), protocol.getName(), forUpdate); + return ensurePlateReplicateStatsDomain(protocol.getContainer(), protocol.getName()); } - private @NotNull Domain ensurePlateReplicateStatsDomain(Container container, String protocolName, boolean forUpdate) + private @NotNull Domain ensurePlateReplicateStatsDomain(Container container, String protocolName) { - Domain domain = getPlateReplicateStatsDomain(container, protocolName, forUpdate); + Domain domain = getPlateReplicateStatsDomain(container, protocolName, true); if (domain == null) domain = PropertyService.get().createDomain(container, getPlateReplicateStatsDomainUri(container, protocolName), PlateReplicateStatsDomainKind.NAME); diff --git a/assay/src/org/labkey/assay/plate/AssayPlateTriggerFactory.java b/assay/src/org/labkey/assay/plate/AssayPlateTriggerFactory.java index 19d9700c0f5..4a095b3f918 100644 --- a/assay/src/org/labkey/assay/plate/AssayPlateTriggerFactory.java +++ b/assay/src/org/labkey/assay/plate/AssayPlateTriggerFactory.java @@ -44,7 +44,7 @@ public AssayPlateTriggerFactory(@NotNull AssayProvider provider, @NotNull ExpPro { _provider = provider; _protocol = protocol; - _qcStateProp = AssayPlateMetadataServiceImpl.getAssayStateProp(provider.getResultsDomain(_protocol)); + _qcStateProp = AssayPlateMetadataServiceImpl.getAssayStateProp(provider.getResultsDomain(_protocol, false)); } @Override diff --git a/core/src/org/labkey/core/query/UsersTable.java b/core/src/org/labkey/core/query/UsersTable.java index 9f2d0095dfa..29056240011 100644 --- a/core/src/org/labkey/core/query/UsersTable.java +++ b/core/src/org/labkey/core/query/UsersTable.java @@ -321,6 +321,12 @@ else if (getColumn(propColumn.getName()) == null) @Override public Domain getDomain() + { + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) { if (getObjectUriColumn() == null) return null; @@ -328,7 +334,7 @@ public Domain getDomain() if (_domain == null) { String domainURI = getDomainURI(); - _domain = PropertyService.get().getDomain(UsersDomainKind.getDomainContainer(), domainURI); + _domain = PropertyService.get().getDomain(UsersDomainKind.getDomainContainer(), domainURI, forUpdate); } return _domain; diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java index 101c353595f..2f7c27ce789 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTableImpl.java @@ -190,7 +190,13 @@ public ExpDataClassDataTableImpl(String name, UserSchema schema, ContainerFilter @Override public Domain getDomain() { - return _dataClass.getDomain(false); + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) + { + return _dataClass.getDomain(forUpdate); } @Override diff --git a/experiment/src/org/labkey/experiment/api/ExpMaterialTableImpl.java b/experiment/src/org/labkey/experiment/api/ExpMaterialTableImpl.java index cade33d0b57..bffd6ea89f5 100644 --- a/experiment/src/org/labkey/experiment/api/ExpMaterialTableImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpMaterialTableImpl.java @@ -866,9 +866,16 @@ private ContainerFilter getSampleStatusLookupContainerFilter() @Override public Domain getDomain() { - return _ss == null ? null : _ss.getDomain(); + return getDomain(false); } + @Override + public Domain getDomain(boolean forUpdate) + { + return _ss == null ? null : _ss.getDomain(forUpdate); + } + + public static String appendNameExpressionDescription(String currentDescription, String nameExpression, String nameExpressionPreview) { if (nameExpression == null) diff --git a/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java b/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java index ebdea9d8609..739acf89d65 100644 --- a/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java +++ b/issues/src/org/labkey/issue/model/IssuesListDefServiceImpl.java @@ -222,12 +222,12 @@ public IssuesListDefProvider getIssuesListDefProvider(String providerName) } @Override - public Domain getDomainFromIssueDefName(String issueDefName, Container container, User user) + public Domain getDomainFromIssueDefName(String issueDefName, Container container, User user, boolean forUpdate) { IssueListDef issueListDef = IssueManager.getIssueListDef(container, issueDefName); if (issueListDef != null) { - return issueListDef.getDomain(user); + return issueListDef.getDomain(user, forUpdate); } return null; diff --git a/issues/src/org/labkey/issue/query/IssuesTable.java b/issues/src/org/labkey/issue/query/IssuesTable.java index 185e8468b3b..4e5d218760f 100644 --- a/issues/src/org/labkey/issue/query/IssuesTable.java +++ b/issues/src/org/labkey/issue/query/IssuesTable.java @@ -393,7 +393,14 @@ public SQLFragment getFromSQL(String alias) @Override public Domain getDomain() { - return _issueDef.getDomain(getUserSchema().getUser()); + return getDomain(false); + } + + @Nullable + @Override + public Domain getDomain(boolean forUpdate) + { + return _issueDef.getDomain(getUserSchema().getUser(), forUpdate); } @Nullable diff --git a/list/src/org/labkey/list/model/ListImporter.java b/list/src/org/labkey/list/model/ListImporter.java index a1da940aaa5..68759f56608 100644 --- a/list/src/org/labkey/list/model/ListImporter.java +++ b/list/src/org/labkey/list/model/ListImporter.java @@ -639,7 +639,7 @@ public ValidatorImporter(int typeId, List properties, public void process() throws Exception { boolean hasValidator = false; - Domain domain = PropertyService.get().getDomain(_typeId); + Domain domain = PropertyService.get().getDomain(_typeId, true); if (null != domain) { @@ -673,7 +673,7 @@ private boolean resolveDomainChanges(Container c, User user, DataLoader loader, if (allowUpdates) { - Domain domain = listDef.getDomain(); + Domain domain = listDef.getDomain(true); boolean isDirty = false; if (domain != null) { diff --git a/list/src/org/labkey/list/model/ListTable.java b/list/src/org/labkey/list/model/ListTable.java index 46ea997d22c..cf1a514f86b 100644 --- a/list/src/org/labkey/list/model/ListTable.java +++ b/list/src/org/labkey/list/model/ListTable.java @@ -390,9 +390,15 @@ public List getDefaultVisibleColumns() @Override public Domain getDomain() + { + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) { if (null != _list) - return _list.getDomain(); + return _list.getDomain(forUpdate); return null; } diff --git a/study/src/org/labkey/study/controllers/StudyController.java b/study/src/org/labkey/study/controllers/StudyController.java index ab4a312eb28..86460710e25 100644 --- a/study/src/org/labkey/study/controllers/StudyController.java +++ b/study/src/org/labkey/study/controllers/StudyController.java @@ -5207,7 +5207,7 @@ private Dataset createDataset(StudySnapshotForm form, BindException errors) thro def.provisionTable(true); } - Domain d = def.getDomain(); + Domain d = def.getDomain(true); for (ColumnInfo col : columnsToProvision) { diff --git a/study/src/org/labkey/study/dataset/DatasetSnapshotProvider.java b/study/src/org/labkey/study/dataset/DatasetSnapshotProvider.java index 24723507f4a..5447e687b45 100644 --- a/study/src/org/labkey/study/dataset/DatasetSnapshotProvider.java +++ b/study/src/org/labkey/study/dataset/DatasetSnapshotProvider.java @@ -559,7 +559,7 @@ private void updateDomainProperties(User user, QuerySnapshotDefinition snapshotD { TableInfo sourceTable = sourceDef.getSchema().getTable(sourceDef.getName(), null); Domain sourceDomain = sourceTable != null ? sourceTable.getDomain() : null; - Domain snapshotDomain = dsDef.getDomain(); + Domain snapshotDomain = dsDef.getDomain(true); // source domain may be null if from a query if (sourceDomain != null && snapshotDomain != null) diff --git a/study/src/org/labkey/study/importer/DefaultStudyDesignImporter.java b/study/src/org/labkey/study/importer/DefaultStudyDesignImporter.java index a459ac43536..fad0f767cc7 100644 --- a/study/src/org/labkey/study/importer/DefaultStudyDesignImporter.java +++ b/study/src/org/labkey/study/importer/DefaultStudyDesignImporter.java @@ -116,7 +116,8 @@ protected void importTableinfo(StudyImportContext ctx, VirtualFile root, String if (table != null) { - final Domain domain = schema.getTable(tableName).getDomain(); + // TODO this is possibly inefficient since we'll be bypassing the cache even if there's nothing new to save + final Domain domain = schema.getTable(tableName).getDomain(true); if (domain != null) { diff --git a/study/src/org/labkey/study/model/DatasetDefinition.java b/study/src/org/labkey/study/model/DatasetDefinition.java index 8920863bdbe..07c29e4300b 100644 --- a/study/src/org/labkey/study/model/DatasetDefinition.java +++ b/study/src/org/labkey/study/model/DatasetDefinition.java @@ -1674,7 +1674,13 @@ public SQLFragment getFromSQL(String alias) @Override public Domain getDomain() { - return DatasetDefinition.this.getDomain(); + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) + { + return DatasetDefinition.this.getDomain(forUpdate); } @Override diff --git a/study/src/org/labkey/study/query/CohortTable.java b/study/src/org/labkey/study/query/CohortTable.java index d18395ef08c..755d9c77df1 100644 --- a/study/src/org/labkey/study/query/CohortTable.java +++ b/study/src/org/labkey/study/query/CohortTable.java @@ -110,6 +110,17 @@ public Domain getDomain() return _domain; } + @Override + public Domain getDomain(boolean forUpdate) + { + if (_domain != null && forUpdate && !_domain.isMutable()) + { + String domainURI = CohortImpl.DOMAIN_INFO.getDomainURI(getContainer()); + _domain = PropertyService.get().getDomain(getContainer(), domainURI, forUpdate); + } + return _domain; + } + @Override public QueryUpdateService getUpdateService() { diff --git a/study/src/org/labkey/study/query/DatasetTableImpl.java b/study/src/org/labkey/study/query/DatasetTableImpl.java index 1384ccc6426..f223cd1de16 100644 --- a/study/src/org/labkey/study/query/DatasetTableImpl.java +++ b/study/src/org/labkey/study/query/DatasetTableImpl.java @@ -662,7 +662,13 @@ protected ColumnInfo resolveColumn(String name) @Override public Domain getDomain() { - return _dsd.getDomain(); + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) + { + return _dsd.getDomain(forUpdate); } @Override diff --git a/study/src/org/labkey/study/query/StudyPropertiesTable.java b/study/src/org/labkey/study/query/StudyPropertiesTable.java index 787c3afc726..8fab4c4c252 100644 --- a/study/src/org/labkey/study/query/StudyPropertiesTable.java +++ b/study/src/org/labkey/study/query/StudyPropertiesTable.java @@ -174,6 +174,18 @@ public Domain getDomain() return _domain; } + + @Override + public Domain getDomain(boolean forUpdate) + { + if (_domain != null && forUpdate && !_domain.isMutable()) + { + String domainURI = StudyImpl.DOMAIN_INFO.getDomainURI(getContainer()); + _domain = PropertyService.get().getDomain(getContainer(), domainURI); + } + return _domain; + } + @Override public boolean hasPermission(@NotNull UserPrincipal user, @NotNull Class perm) { diff --git a/survey/src/org/labkey/survey/query/SurveysTable.java b/survey/src/org/labkey/survey/query/SurveysTable.java index a624d57dfef..f7c1b727377 100644 --- a/survey/src/org/labkey/survey/query/SurveysTable.java +++ b/survey/src/org/labkey/survey/query/SurveysTable.java @@ -103,6 +103,12 @@ public SimpleTableDomainKind getDomainKind() @Override public Domain getDomain() + { + return getDomain(false); + } + + @Override + public Domain getDomain(boolean forUpdate) { if (getObjectUriColumn() == null) return null; @@ -110,7 +116,7 @@ public Domain getDomain() if (_domain == null) { String domainURI = getDomainURI(); - _domain = PropertyService.get().getDomain(SurveyTableDomainKind.getDomainContainer(getContainer()), domainURI); + _domain = PropertyService.get().getDomain(SurveyTableDomainKind.getDomainContainer(getContainer()), domainURI, forUpdate); } return _domain; } From a6aca25a2095964f1d4b939c6c857496af92b763 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 28 May 2025 11:17:05 -0700 Subject: [PATCH 15/17] Use the forUpdate parameter --- study/src/org/labkey/study/query/StudyPropertiesTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/study/src/org/labkey/study/query/StudyPropertiesTable.java b/study/src/org/labkey/study/query/StudyPropertiesTable.java index 8fab4c4c252..faf4382c38e 100644 --- a/study/src/org/labkey/study/query/StudyPropertiesTable.java +++ b/study/src/org/labkey/study/query/StudyPropertiesTable.java @@ -181,7 +181,7 @@ public Domain getDomain(boolean forUpdate) if (_domain != null && forUpdate && !_domain.isMutable()) { String domainURI = StudyImpl.DOMAIN_INFO.getDomainURI(getContainer()); - _domain = PropertyService.get().getDomain(getContainer(), domainURI); + _domain = PropertyService.get().getDomain(getContainer(), domainURI, forUpdate); } return _domain; } From bb2415a1ae8296c3bd2ff2104862fbaf613908ab Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 2 Jun 2025 16:33:05 -0700 Subject: [PATCH 16/17] Comments --- api/src/org/labkey/api/assay/AssayProvider.java | 1 + api/src/org/labkey/api/exp/property/PropertyService.java | 1 + .../src/org/labkey/experiment/api/ExpDataClassImpl.java | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/api/src/org/labkey/api/assay/AssayProvider.java b/api/src/org/labkey/api/assay/AssayProvider.java index 5232baba43b..8e559d4eba3 100644 --- a/api/src/org/labkey/api/assay/AssayProvider.java +++ b/api/src/org/labkey/api/assay/AssayProvider.java @@ -97,6 +97,7 @@ enum ReRunSupport /** Get a schema that includes queries like Batch, Run, Results, and any additional tables. */ AssayProtocolSchema createProtocolSchema(User user, Container container, @NotNull ExpProtocol protocol, @Nullable Container targetStudy); + /** Get a domain that is not intended to be mutated */ Domain getBatchDomain(ExpProtocol protocol); Domain getBatchDomain(ExpProtocol protocol, boolean forUpdate); diff --git a/api/src/org/labkey/api/exp/property/PropertyService.java b/api/src/org/labkey/api/exp/property/PropertyService.java index de26950fea8..88552a91c7f 100644 --- a/api/src/org/labkey/api/exp/property/PropertyService.java +++ b/api/src/org/labkey/api/exp/property/PropertyService.java @@ -58,6 +58,7 @@ static void setInstance(PropertyService impl) @Nullable Domain getDomain(Container container, String domainURI, boolean forUpdate); + /** Get a domain that is not intended for update */ @Nullable Domain getDomain(int domainId); diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java index 8cbb9576e45..098a65a5259 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassImpl.java @@ -255,6 +255,10 @@ public Domain getDomain(boolean forUpdate) throw UnexpectedException.wrap(e); } } + if (_domain != null && !forUpdate && _domain.isMutable()) + _domain = PropertyService.get().getDomain(getContainer(), getLSID(), false); + if (_domain == null) // this should really never be true + throw new IllegalStateException("Domain does not exist."); } return _domain; } From d4c11b4d70129172c35450eb6196bf60fae3a030 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 2 Jun 2025 16:33:39 -0700 Subject: [PATCH 17/17] Better handling of forUpdate and stashed objects --- api/src/org/labkey/api/data/SchemaTableInfo.java | 2 ++ api/src/org/labkey/api/query/SimpleUserSchema.java | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/api/src/org/labkey/api/data/SchemaTableInfo.java b/api/src/org/labkey/api/data/SchemaTableInfo.java index 3ff1f3fa94a..3df40b08008 100644 --- a/api/src/org/labkey/api/data/SchemaTableInfo.java +++ b/api/src/org/labkey/api/data/SchemaTableInfo.java @@ -861,6 +861,8 @@ public Domain getDomain() @Override public Domain getDomain(boolean forUpdate) { + if (forUpdate) + throw new UnsupportedOperationException("Cannot get domain for update."); return getDomain(); } diff --git a/api/src/org/labkey/api/query/SimpleUserSchema.java b/api/src/org/labkey/api/query/SimpleUserSchema.java index d7f7bf720f7..69d4b9ea265 100644 --- a/api/src/org/labkey/api/query/SimpleUserSchema.java +++ b/api/src/org/labkey/api/query/SimpleUserSchema.java @@ -468,10 +468,10 @@ public Domain getDomain(boolean forUpdate) return null; if (_domain == null || (forUpdate && !_domain.isMutable())) - { - String domainURI = getDomainURI(); - _domain = PropertyService.get().getDomain(getDomainContainer(), domainURI, forUpdate); - } + _domain = PropertyService.get().getDomain(getDomainContainer(), getDomainURI(), forUpdate); + + if (_domain != null && !forUpdate && _domain.isMutable()) + _domain = PropertyService.get().getDomain(getDomainContainer(), getDomainURI(), forUpdate); return _domain; }