diff --git a/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstanceController.java b/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstanceController.java index 097d2709c..8563e9bb3 100644 --- a/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstanceController.java +++ b/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstanceController.java @@ -65,6 +65,7 @@ import de.metas.ui.web.window.model.IDocumentChangesCollector.ReasonSupplier; import de.metas.ui.web.window.model.IDocumentFieldView; import de.metas.ui.web.window.model.NullDocumentChangesCollector; +import lombok.NonNull; /* * #%L @@ -112,7 +113,7 @@ public static final Builder builder() private final IViewsRepository viewsRepo; private final ViewId viewId; private final DocumentIdsSelection viewSelectedDocumentIds; - + private final DocumentPath contextSingleDocumentPath; private boolean executed = false; @@ -131,7 +132,7 @@ private ADProcessInstanceController(final Builder builder) viewsRepo = builder.viewsRepo; viewId = builder.viewId; viewSelectedDocumentIds = builder.viewSelectedDocumentIds == null ? DocumentIdsSelection.EMPTY : builder.viewSelectedDocumentIds; - + contextSingleDocumentPath = builder.contextSingleDocumentPath; executed = false; @@ -154,7 +155,7 @@ private ADProcessInstanceController(final ADProcessInstanceController from, fina viewsRepo = from.viewsRepo; viewId = from.viewId; viewSelectedDocumentIds = from.viewSelectedDocumentIds; - + contextSingleDocumentPath = from.contextSingleDocumentPath; executed = from.executed; @@ -201,17 +202,21 @@ public ADProcessInstanceController copy(final CopyMode copyMode, final IDocument { return new ADProcessInstanceController(this, copyMode, changesCollector); } - - public ADProcessInstanceController bindContextSingleDocument(final DocumentCollection documentsCollection) + + public ADProcessInstanceController bindContextSingleDocumentIfPossible(@NonNull final DocumentCollection documentsCollection) { - if(contextSingleDocumentPath == null) + if (contextSingleDocumentPath == null) + { + return this; + } + if (!documentsCollection.isWindowIdSupported(contextSingleDocumentPath.getWindowIdOrNull())) { return this; } - + final Document contextSingleDocument = documentsCollection.forDocumentReadonly(contextSingleDocumentPath, NullDocumentChangesCollector.instance, Function.identity()); getParametersDocument().setShadowParentDocumentEvaluatee(contextSingleDocument.asEvaluatee()); - + return this; } @@ -344,7 +349,7 @@ else if (recordsToOpen != null && recordsToOpen.getTarget() == OpenTarget.GridVi final String parentViewIdStr = processExecutionResult.getWebuiViewId(); final ViewId parentViewId = parentViewIdStr != null ? ViewId.ofViewIdString(parentViewIdStr) : null; final CreateViewRequest viewRequest = createViewRequest(recordsToOpen, referencingDocumentPaths, parentViewId); - + final IView view = viewsRepo.createView(viewRequest); resultBuilder.setAction(OpenViewAction.builder() .viewId(view.getViewId()) @@ -573,11 +578,10 @@ public static class Builder private IViewsRepository viewsRepo; private ViewId viewId; private DocumentIdsSelection viewSelectedDocumentIds; - + private Object processClassInstance; - + private DocumentPath contextSingleDocumentPath; - private Builder() { @@ -625,7 +629,7 @@ public Builder setProcessClassInstance(final Object processClassInstance) this.processClassInstance = processClassInstance; return this; } - + public Builder setContextSingleDocumentPath(final DocumentPath contextSingleDocumentPath) { this.contextSingleDocumentPath = contextSingleDocumentPath; diff --git a/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstancesRepository.java b/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstancesRepository.java index 888d530fc..50a06e49c 100644 --- a/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstancesRepository.java +++ b/src/main/java/de/metas/ui/web/process/adprocess/ADProcessInstancesRepository.java @@ -344,8 +344,10 @@ public R forProcessInstanceReadonly(final DocumentId pinstanceId, final Func { try (final IAutoCloseable readLock = getOrLoad(pinstanceId).lockForReading()) { - final ADProcessInstanceController processInstance = getOrLoad(pinstanceId).copy(CopyMode.CheckInReadonly, NullDocumentChangesCollector.instance) - .bindContextSingleDocument(documentsCollection); + final ADProcessInstanceController processInstance = getOrLoad(pinstanceId) + .copy(CopyMode.CheckInReadonly, NullDocumentChangesCollector.instance) + .bindContextSingleDocumentIfPossible(documentsCollection); + try (final IAutoCloseable c = processInstance.activate()) { return processor.apply(processInstance); @@ -370,8 +372,9 @@ public R forProcessInstanceWritable(final DocumentId pinstanceId, final IDoc { try (final IAutoCloseable writeLock = getOrLoad(pinstanceId).lockForWriting()) { - final ADProcessInstanceController processInstance = getOrLoad(pinstanceId).copy(CopyMode.CheckOutWritable, changesCollector) - .bindContextSingleDocument(documentsCollection); + final ADProcessInstanceController processInstance = getOrLoad(pinstanceId) + .copy(CopyMode.CheckOutWritable, changesCollector) + .bindContextSingleDocumentIfPossible(documentsCollection); // Make sure the process was not already executed. // If it was executed we are not allowed to change it. diff --git a/src/main/java/de/metas/ui/web/window/descriptor/factory/DocumentDescriptorFactory.java b/src/main/java/de/metas/ui/web/window/descriptor/factory/DocumentDescriptorFactory.java index 00d5dd476..2373c501f 100644 --- a/src/main/java/de/metas/ui/web/window/descriptor/factory/DocumentDescriptorFactory.java +++ b/src/main/java/de/metas/ui/web/window/descriptor/factory/DocumentDescriptorFactory.java @@ -34,6 +34,14 @@ public interface DocumentDescriptorFactory { + /** + * Tell the caller if they can expect this instance's methods to work with the given {@code windowId}. + * + * @param windowId may be {@code null}. If {@code null}, then return {@code false}. + * @return + */ + boolean isWindowIdSupported(WindowId windowId); + DocumentDescriptor getDocumentDescriptor(WindowId windowId) throws DocumentLayoutBuildException; default DocumentEntityDescriptor getDocumentEntityDescriptor(final int AD_Window_ID) @@ -41,7 +49,7 @@ default DocumentEntityDescriptor getDocumentEntityDescriptor(final int AD_Window final WindowId windowId = WindowId.of(AD_Window_ID); return getDocumentDescriptor(windowId).getEntityDescriptor(); } - + default DocumentEntityDescriptor getDocumentEntityDescriptor(@NonNull final WindowId windowId) { return getDocumentDescriptor(windowId).getEntityDescriptor(); @@ -64,7 +72,7 @@ default String getTableNameOrNull(final int AD_Window_ID, final DetailId detailI return descriptor.getIncludedEntityByDetailId(detailId).getTableName(); } } - + default DocumentEntityDescriptor getDocumentEntityDescriptor(final DocumentPath documentPath) { final DocumentEntityDescriptor rootEntityDescriptor = getDocumentEntityDescriptor(documentPath.getWindowId()); @@ -78,7 +86,7 @@ default DocumentEntityDescriptor getDocumentEntityDescriptor(final DocumentPath return rootEntityDescriptor.getIncludedEntityByDetailId(documentPath.getDetailId()); } } - + default TableRecordReference getTableRecordReference(final DocumentPath documentPath) { final DocumentEntityDescriptor rootEntityDescriptor = getDocumentEntityDescriptor(documentPath.getWindowId()); @@ -95,5 +103,4 @@ default TableRecordReference getTableRecordReference(final DocumentPath document final int recordId = documentPath.getSingleRowId().toInt(); return TableRecordReference.of(tableName, recordId); } - } diff --git a/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java b/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java index 781cfc825..903e4d347 100644 --- a/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java +++ b/src/main/java/de/metas/ui/web/window/descriptor/factory/standard/DefaultDocumentDescriptorFactory.java @@ -1,5 +1,7 @@ package de.metas.ui.web.window.descriptor.factory.standard; +import javax.annotation.Nullable; + import org.compiere.model.I_AD_Window; import org.compiere.util.CCache; import org.springframework.stereotype.Service; @@ -22,11 +24,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% */ @@ -38,7 +40,6 @@ public class DefaultDocumentDescriptorFactory implements DocumentDescriptorFacto /* package */ DefaultDocumentDescriptorFactory() { - super(); } @Override @@ -53,4 +54,13 @@ public DocumentDescriptor getDocumentDescriptor(final WindowId windowId) throw DocumentLayoutBuildException.wrapIfNeeded(e); } } + + /** + * @return {@code true} if the given {@code windowId} is not-{@code null} and embeds an int value. + */ + @Override + public boolean isWindowIdSupported(@Nullable final WindowId windowId) + { + return windowId == null ? false :windowId.isInt(); + } } diff --git a/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java b/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java index 0b5879841..cc9d5f04f 100644 --- a/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java +++ b/src/main/java/de/metas/ui/web/window/model/DocumentCollection.java @@ -8,6 +8,7 @@ import java.util.concurrent.ExecutionException; import java.util.function.Function; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import org.adempiere.ad.expression.api.IExpressionEvaluator.OnVariableNotFound; @@ -113,11 +114,23 @@ public class DocumentCollection super(); } + public DocumentDescriptorFactory getDocumentDescriptorFactory() { return documentDescriptorFactory; } + /** + * Delegates to the {@link DocumentDescriptorFactory#isWindowIdSupported(WindowId)} of this instance's {@code documentDescriptorFactory}. + * + * @param windowId + * @return + */ + public boolean isWindowIdSupported(@Nullable final WindowId windowId) + { + return documentDescriptorFactory.isWindowIdSupported(windowId); + } + public final DocumentDescriptor getDocumentDescriptor(final WindowId windowId) { return documentDescriptorFactory.getDocumentDescriptor(windowId); @@ -147,7 +160,10 @@ private final Set getCachedWindowIdsForTableName(final String tableNam return windowIds != null && !windowIds.isEmpty() ? ImmutableSet.copyOf(windowIds) : ImmutableSet.of(); } - public R forDocumentReadonly(final DocumentPath documentPath, final IDocumentChangesCollector changesCollector, final Function documentProcessor) + public R forDocumentReadonly( + @NonNull final DocumentPath documentPath, + final IDocumentChangesCollector changesCollector, + final Function documentProcessor) { final DocumentPath rootDocumentPath = documentPath.getRootDocumentPath(); @@ -170,7 +186,7 @@ else if (documentPath.isSingleIncludedDocument()) }); } - private Document getOrLoadDocument(final DocumentKey documentKey) + private Document getOrLoadDocument(@NonNull final DocumentKey documentKey) { try { @@ -186,7 +202,10 @@ private Document getOrLoadDocument(final DocumentKey documentKey) } } - public R forRootDocumentReadonly(final DocumentPath documentPath, final IDocumentChangesCollector changesCollector, final Function rootDocumentProcessor) + public R forRootDocumentReadonly( + @NonNull final DocumentPath documentPath, + final IDocumentChangesCollector changesCollector, + final Function rootDocumentProcessor) { final DocumentKey rootDocumentKey = DocumentKey.ofRootDocumentPath(documentPath.getRootDocumentPath()); @@ -199,7 +218,10 @@ public R forRootDocumentReadonly(final DocumentPath documentPath, final IDoc } } - public R forDocumentWritable(final DocumentPath documentPath, final IDocumentChangesCollector changesCollector, final Function documentProcessor) + public R forDocumentWritable( + @NonNull final DocumentPath documentPath, + final IDocumentChangesCollector changesCollector, + final Function documentProcessor) { final DocumentPath rootDocumentPath = documentPath.getRootDocumentPath(); return forRootDocumentWritable(rootDocumentPath, changesCollector, rootDocument -> { @@ -589,7 +611,7 @@ public void invalidateDocumentByRecordId(final String tableName, final int recor websocketSender.convertAndSend(event.getWebsocketEndpoint(), event); }); } - + /** * Invalidates all root documents identified by tableName/recordId and notifies frontend (via websocket). * @@ -609,21 +631,20 @@ public void invalidateRootDocument(@NonNull final DocumentPath documentPath) final JSONDocumentChangedWebSocketEvent event = JSONDocumentChangedWebSocketEvent.staleRootDocument(documentKey.getWindowId(), documentKey.getDocumentId()); websocketSender.convertAndSend(event.getWebsocketEndpoint(), event); } - + public Document duplicateDocument(final DocumentPath fromDocumentPath) { final TableRecordReference fromRecordRef = getTableRecordReference(fromDocumentPath); - + final Object fromModel = fromRecordRef.getModel(PlainContextAware.newWithThreadInheritedTrx()); final String tableName = InterfaceWrapperHelper.getModelTableName(fromModel); final PO fromPO = InterfaceWrapperHelper.getPO(fromModel); - - + final PO toPO = TableModelLoader.instance.newPO(Env.getCtx(), tableName, ITrx.TRXNAME_ThreadInherited); toPO.setDynAttribute(PO.DYNATTR_CopyRecordSupport, CopyRecordFactory.getCopyRecordSupport(tableName)); // set "getValueToCopy" advisor PO.copyValues(fromPO, toPO, true); InterfaceWrapperHelper.save(toPO); - + final CopyRecordSupport childCRS = CopyRecordFactory.getCopyRecordSupport(tableName); childCRS.setAD_Window_ID(fromDocumentPath.getAD_Window_ID(-1)); childCRS.setParentPO(toPO); @@ -633,7 +654,7 @@ public Document duplicateDocument(final DocumentPath fromDocumentPath) final DocumentPath toDocumentPath = DocumentPath.rootDocumentPath(fromDocumentPath.getWindowId(), DocumentId.of(toPO.get_ID())); return forDocumentReadonly(toDocumentPath, NullDocumentChangesCollector.instance, Function.identity()); } - + public BoilerPlateContext createBoilerPlateContext(final DocumentPath documentPath) { if (documentPath == null) @@ -646,7 +667,7 @@ public BoilerPlateContext createBoilerPlateContext(final DocumentPath documentPa return MADBoilerPlate.createEditorContext(sourceDocument); }); } - + @AllArgsConstructor private static final class DocumentAsTemplateSourceDocument implements SourceDocument { @@ -672,7 +693,6 @@ public int getFieldValueAsInt(final String fieldName, final int defaultValue) } } - @Immutable @Value @Builder