package jnpf.dmsService; import jnpf.dmsBusinessOccupancy.BusinessFileExpiryGate; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.UUID; /** One coordinated rollout switch. Must stay off until acquisition, completion and all consumers pass. */ @Component public class DmsBusinessLifecycleGuard { private final boolean enabled; private final BusinessFileExpiryGate expiry; private final jnpf.dmsBusinessOccupancy.BusinessFileExecutionService execution; public DmsBusinessLifecycleGuard(SqlSessionTemplate sessions, @Value("${dms.business-occupancy.enabled:false}") boolean enabled) { this.enabled = enabled; this.execution = enabled ? new jnpf.dmsBusinessOccupancy.BusinessFileExecutionService(sessions) : null; this.expiry = enabled ? new BusinessFileExpiryGate(sessions) : null; } /** Native source is reconstructed by the approved audit loader; no posted subset or chain. */ public void requireAuditSource(jnpf.dmsEntity.storage.approval.DmsApprovedBatch source) { if(!enabled) return; var rows = "wailai_wenjian_xinzeng_shenhe".equals(source.getAuditType()) ? requireExternalCreation(source) : "xiuding_shenhe".equals(source.getAuditType()) ? execution.requireRevision(source.getTenantId(),source.getAuditId()) : execution.requireCreation(source.getTenantId(),source.getAuditId()); verifySourceCoverage(rows,source.getItems()); } private java.util.List requireExternalCreation( jnpf.dmsEntity.storage.approval.DmsApprovedBatch source) { if (source.getItems() == null || source.getItems().size() != 1 || !"CREATE".equals(source.getItems().get(0).getChangeType())) throw new jnpf.exception.DataException("外来文件批准来源必须只有一份新文件"); return execution.requireExternalCreation(source.getTenantId(), source.getAuditId(), source.getTaskId(), source.getItems().get(0).getDocumentNo()); } /** Exact one-to-one match before center registration/activation; caller already verified receipts. */ public static void verifySourceCoverage(java.util.List businessReceipts, java.util.List items) { var numbers=new java.util.HashSet(); for(var item:items) { var matching=businessReceipts.stream().filter(row->"CREATE".equals(item.getChangeType()) ? "CREATE".equals(row.getOperation()) && java.util.Objects.equals(item.getDocumentNo(),row.getFileNumber()) : item.getBaseFileVersionId()!=null && java.util.Objects.equals(item.getBaseFileVersionId().toString(),row.getCenterVersionId())) .toList(); if(matching.size()!=1 || !numbers.add(matching.get(0).getFileNumber())) throw new jnpf.exception.DataException("审核来源没有唯一匹配的业务占用"); } if(numbers.size()!=businessReceipts.size()) throw new jnpf.exception.DataException("审核来源与业务占用集合不一致"); } public boolean isEnabled() { return enabled; } public void guardStandaloneActivation(String tenant,UUID versionId) { if(enabled) execution.guardStandaloneActivation(tenant,versionId.toString()); } public void guardStandaloneRegistration(String tenant,String fileNumber) { if(enabled) execution.guardStandaloneRegistration(tenant,fileNumber); } public java.util.List requireCurrentUserExtension( String task,String application,java.util.Collection fileIds) { if(!enabled) return java.util.List.of(); String tenant=jnpf.util.UserProvider.getUser().getTenantId(); return execution.requireExtension(tenant==null || tenant.isBlank() ? "0" : tenant,application,task,fileIds); } public java.util.List requireCurrentUserExecution( String task,String application,String operation,java.util.Collection fileIds) { if(!enabled) return java.util.List.of(); String tenant=jnpf.util.UserProvider.getUser().getTenantId(); return execution.require(tenant==null || tenant.isBlank() ? "0" : tenant,task,application,task,operation,fileIds); } public java.util.List requireExecution( String tenant,String task,String application,String operation,java.util.Collection fileIds) { return enabled ? execution.require(tenant,task,application,task,operation,fileIds) : java.util.List.of(); } public java.util.List requireRevision(String tenant,String auditId) { return enabled ? execution.requireRevision(tenant,auditId) : java.util.List.of(); } public java.util.List requireCreation(String tenant,String auditId) { return enabled ? execution.requireCreation(tenant,auditId) : java.util.List.of(); } public java.util.List requireExternalCreation( String tenant, String auditId, String taskId, String fileNumber) { return enabled ? execution.requireExternalCreation(tenant, auditId, taskId, fileNumber) : java.util.List.of(); } public void guardValidity(String tenant,String task,java.util.Collection versions) { if(enabled) execution.guardValidity(tenant,task,versions); } public void guardNumbers(String tenant,String chain,java.util.Collection numbers) { if(enabled) execution.guardNumbers(tenant,chain,numbers); } public void guardVersions(String tenant,String chain,java.util.Collection versions) { if(enabled) execution.guardVersions(tenant,chain,versions); } public void completeExecution(java.util.List receipts) { if(enabled) execution.complete(receipts); } public java.util.List terminationCandidates(String afterId,int limit) { return enabled ? execution.terminationCandidates(afterId,limit) : java.util.List.of(); } @org.springframework.transaction.annotation.Transactional(rollbackFor=Exception.class) public boolean releaseEnded(jnpf.dmsBusinessOccupancy.BusinessFileOccupancy candidate) { return enabled && execution.releaseEnded(candidate); } public boolean tryEnterExpiry(String tenantId, UUID centerVersionId) { return !enabled || expiry.tryEnter(tenantId, centerVersionId.toString()); } }