From 3e7acdb764cbb83c9054ffec3e30f29d683a657a Mon Sep 17 00:00:00 2001 From: Teo Sarca Date: Thu, 2 Mar 2017 10:25:47 +0200 Subject: [PATCH] #19 invalidate included documents --- .../descriptor/DocumentEntityDescriptor.java | 41 +++++++++++-------- .../factory/DocumentDescriptorFactory.java | 24 +++++------ .../DefaultDocumentDescriptorFactory.java | 21 ++++++++-- .../metas/ui/web/window/model/Document.java | 15 ++++++- .../web/window/model/DocumentCollection.java | 23 ++++++++--- 5 files changed, 83 insertions(+), 41 deletions(-) diff --git a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/DocumentEntityDescriptor.java b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/DocumentEntityDescriptor.java index b276f1d20..6d2e12228 100644 --- a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/DocumentEntityDescriptor.java +++ b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/DocumentEntityDescriptor.java @@ -12,6 +12,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.Nullable; @@ -62,11 +63,11 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public - * License along with this program. If not, see + * License along with this program. If not, see * . * #L% */ @@ -283,10 +284,10 @@ private Set buildFieldsWithCharacteristic(final Characteristic character return getFields() .stream() .filter(field -> field.hasCharacteristic(characteristic)) - .map(field->field.getFieldName()) + .map(field -> field.getFieldName()) .collect(GuavaCollectors.toImmutableSet()); } - + public IIncludedDocumentsCollection createIncludedDocumentsCollection(final Document parentDocument) { return includedDocumentsCollectionFactory.createIncludedDocumentsCollection(parentDocument, this); @@ -312,11 +313,18 @@ public DocumentEntityDescriptor getIncludedEntityByDetailId(final DetailId detai return includedEntityDescriptor; } + public Stream getIncludedEntitiesByTableName(final String tableName) + { + return includedEntitiesByDetailId.values() + .stream() + .filter(entityDescriptor -> tableName.equals(entityDescriptor.getTableNameOrNull())); + } + public DocumentEntityDataBindingDescriptor getDataBinding() { return dataBinding; } - + public boolean isHighVolume() { return highVolume; @@ -425,7 +433,6 @@ public static final class Builder private Optional _tableName = Optional.empty(); private Optional _isSOTrx = Optional.empty(); - private Builder() { super(); @@ -563,7 +570,7 @@ public String getIdFieldName() .stream() .filter(fieldBuilder -> fieldBuilder.isKey()) .collect(Collectors.toList()); - if(idFields.isEmpty()) + if (idFields.isEmpty()) { return null; } @@ -602,7 +609,7 @@ public Map buildIncludedEntitiesByDetailId() { return ImmutableMap.copyOf(_includedEntitiesByDetailId); } - + public IIncludedDocumentsCollectionFactory getIncludedDocumentsCollectionFactory() { if (isHighVolume()) @@ -614,15 +621,14 @@ public IIncludedDocumentsCollectionFactory getIncludedDocumentsCollectionFactory else { // TODO implement an IIncludedDocumentCollection which does not cache the documents but which allows New/Delete - // Case: e.g. Product->Price, Product->CU-TU etc + // Case: e.g. Product->Price, Product->CU-TU etc } } - + // Fallback - return IncludedDocumentsCollection::new; + return IncludedDocumentsCollection::new; } - public Builder setDataBinding(final DocumentEntityDataBindingDescriptorBuilder dataBindingBuilder) { _dataBinding = dataBindingBuilder; @@ -641,19 +647,18 @@ private DocumentEntityDataBindingDescriptor getOrBuildDataBinding() Preconditions.checkNotNull(_dataBinding, "dataBinding"); return _dataBinding.getOrBuild(); } - + public Builder setHighVolume(final boolean highVolume) { this._highVolume = highVolume; return this; } - + public boolean isHighVolume() { return _highVolume; } - private DocumentFieldDependencyMap buildDependencies() { final DocumentFieldDependencyMap.Builder dependenciesBuilder = DocumentFieldDependencyMap.builder(); @@ -667,7 +672,7 @@ public Builder setDocumentType(final DocumentType documentType, final DocumentId _documentTypeId = documentTypeId; return this; } - + public Builder setDocumentType(final DocumentType documentType, final int documentTypeIdInt) { setDocumentType(documentType, DocumentId.of(documentTypeIdInt)); @@ -724,7 +729,7 @@ public String getTableNameOrNull() { return _tableName.orElse(null); } - + public boolean isTableName(final String expectedTableName) { return Objects.equals(expectedTableName, _tableName.orElse(null)); @@ -912,7 +917,7 @@ private ICalloutExecutor buildCalloutExecutorFactory(final Collection getDocumentPaths(String tableName, int recordIdInt); + List getDocumentPaths(String tableName, int documentIdInt, String includedTableName, int includedDocumentIdInt); } diff --git a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java index 4cf9b91f3..80c3b4a93 100644 --- a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java +++ b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Set; +import java.util.stream.Stream; import org.adempiere.util.Check; import org.compiere.model.I_AD_Window; @@ -14,6 +15,7 @@ import de.metas.ui.web.window.datatypes.DocumentId; import de.metas.ui.web.window.datatypes.DocumentPath; +import de.metas.ui.web.window.datatypes.DocumentType; import de.metas.ui.web.window.descriptor.DocumentDescriptor; import de.metas.ui.web.window.descriptor.DocumentEntityDescriptor; import de.metas.ui.web.window.descriptor.factory.DocumentDescriptorFactory; @@ -87,13 +89,26 @@ private Set getEntityDescriptorsForTableName(final Str } @Override - public List getDocumentPaths(final String tableName, final int recordIdInt) + public List getDocumentPaths(final String tableName, final int documentIdInt, final String includedTableName, final int includedDocumentIdInt) { - final DocumentId recordId = DocumentId.of(recordIdInt); + final DocumentId documentId = DocumentId.of(documentIdInt); return getEntityDescriptorsForTableName(tableName) .stream() - .map(entityDescriptor -> DocumentPath.rootDocumentPath(entityDescriptor.getDocumentType(), entityDescriptor.getDocumentTypeId(), recordId)) + .flatMap(entityDescriptor -> { + final DocumentType documentType = entityDescriptor.getDocumentType(); + final DocumentId documentTypeId = entityDescriptor.getDocumentTypeId(); + if (includedTableName == null) + { + return Stream.of(DocumentPath.rootDocumentPath(documentType, documentTypeId, documentId)); + } + else + { + final DocumentId rowId = DocumentId.of(includedDocumentIdInt); + return entityDescriptor.getIncludedEntitiesByTableName(includedTableName) + .map(includedEntityDescriptor -> DocumentPath.includedDocumentPath(documentType, documentTypeId, documentId, includedEntityDescriptor.getDetailId(), rowId)); + } + }) .collect(ImmutableList.toImmutableList()); } } diff --git a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/Document.java b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/Document.java index 200767c82..6018d67b5 100644 --- a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/Document.java +++ b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/Document.java @@ -702,13 +702,13 @@ public Document copy(final CopyMode copyMode) { return; } - + if (!isWritable()) { throw new InvalidDocumentStateException(this, "not a writable copy"); } - if(isDeleted()) + if (isDeleted()) { throw new DocumentNotFoundException(getDocumentPath()); } @@ -1643,6 +1643,12 @@ private DocumentStaleState getStale() return _staleStatus.isStaled(); } + /* package */void markStaled() + { + _staleStatus.markStaled(); + // includedDocuments.values().forEach(includedDocumentsForDetail -> includedDocumentsForDetail.markStaleAll()); + } + public IAutoCloseable lockForReading() { // assume _lock is not null @@ -1725,6 +1731,11 @@ private boolean checkStaled() return true; } + private void markStaled() + { + staled = true; + } + private void markNotStaled(final String version) { staled = false; diff --git a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java index 6cc310160..67ef16bf3 100644 --- a/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java +++ b/metasfresh-webui-api/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java @@ -9,6 +9,7 @@ import org.adempiere.util.Check; import org.adempiere.util.lang.IAutoCloseable; import org.adempiere.util.lang.impl.TableRecordReference; +import org.compiere.util.CacheInvalidateRequest; import org.compiere.util.CacheMgt; import org.compiere.util.CacheMgtListener; import org.slf4j.Logger; @@ -86,12 +87,17 @@ public Document load(final DocumentKey documentKey) }); - private CacheMgtListener cacheMgtListener = new CacheMgtListener() + private final CacheMgtListener cacheMgtListener = new CacheMgtListener() { @Override - public void onReset(String tableName, int recordId) + public void onReset(final CacheInvalidateRequest request) { - getDocumentPaths(tableName, recordId) + final String tableName = request.getTableName(); + final int documentId = request.getRecordId(); + final boolean hasChild = request.hasChild(); + final String includedTableName = hasChild ? request.getChildTableName() : null; + final int includedDocumentIdInt = hasChild ? request.getChildRecordId() : -1; + getDocumentPaths(tableName, documentId, includedTableName, includedDocumentIdInt) .forEach(documentPath -> invalidateDocumentByPath(documentPath)); } }; @@ -259,7 +265,12 @@ public R forRootDocumentWritable(final DocumentPath documentPathOrNew, final private final void invalidateDocumentByPath(final DocumentPath documentPath) { - forDocumentReadonlyIfLoaded(documentPath, document -> document.refreshFromRepository()); + forDocumentReadonlyIfLoaded(documentPath, document -> { + document.markStaled(); + + // TODO: if it's in current scope, shall we also refresh it??? + document.refreshFromRepositoryIfStaled(); + }); } /** @@ -391,9 +402,9 @@ public TableRecordReference getTableRecordReference(final DocumentPath documentP return documentDescriptorFactory.getTableRecordReference(documentPath); } - public List getDocumentPaths(final String tableName, final int recordIdInt) + public List getDocumentPaths(final String tableName, final int recordIdInt, final String includedTableName, final int includedDocumentIdInt) { - return documentDescriptorFactory.getDocumentPaths(tableName, recordIdInt); + return documentDescriptorFactory.getDocumentPaths(tableName, recordIdInt, includedTableName, includedDocumentIdInt); } public DocumentAttachments getDocumentAttachments(final DocumentPath documentPath)