mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Compare commits
3 Commits
25.3.0.52
...
feature/AC
Author | SHA1 | Date | |
---|---|---|---|
|
8986d03a2f | ||
|
502c996c9e | ||
|
a22e7d23f0 |
@@ -139,3 +139,11 @@ content.metadata.async.extract.6.enabled=false
|
|||||||
|
|
||||||
# Max number of entries returned in Record search view
|
# Max number of entries returned in Record search view
|
||||||
rm.recordSearch.maxItems=500
|
rm.recordSearch.maxItems=500
|
||||||
|
|
||||||
|
#
|
||||||
|
# Hold bulk
|
||||||
|
#
|
||||||
|
rm.hold.bulk.threadCount=2
|
||||||
|
rm.hold.bulk.maxItems=1000
|
||||||
|
rm.hold.bulk.batchSize=100
|
||||||
|
rm.hold.bulk.logging.interval.ms=1000
|
||||||
|
@@ -83,6 +83,13 @@
|
|||||||
<property name="nodesModelFactory" ref="nodesModelFactory" />
|
<property name="nodesModelFactory" ref="nodesModelFactory" />
|
||||||
<property name="fileFolderService" ref="FileFolderService" />
|
<property name="fileFolderService" ref="FileFolderService" />
|
||||||
<property name="transactionService" ref="transactionService" />
|
<property name="transactionService" ref="transactionService" />
|
||||||
|
<property name="holdBulkService" ref="holdBulkService" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean class="org.alfresco.rm.rest.api.holds.HoldsBulkStatusesRelation" >
|
||||||
|
<property name="holdBulkMonitor" ref="holdBulkMonitor" />
|
||||||
|
<property name="apiUtils" ref="apiUtils" />
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean class="org.alfresco.rm.rest.api.holds.HoldsChildrenRelation">
|
<bean class="org.alfresco.rm.rest.api.holds.HoldsChildrenRelation">
|
||||||
@@ -257,4 +264,42 @@
|
|||||||
<property name="beanName" value="restJsonModule" />
|
<property name="beanName" value="restJsonModule" />
|
||||||
<property name="extendingBeanName" value="rm.restJsonModule" />
|
<property name="extendingBeanName" value="rm.restJsonModule" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="holdBulkService"
|
||||||
|
class="org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkServiceImpl">
|
||||||
|
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||||
|
<property name="transactionService" ref="transactionService" />
|
||||||
|
<property name="searchMapper" ref="searchapiSearchMapper" />
|
||||||
|
<property name="bulkMonitor" ref="holdBulkMonitor" />
|
||||||
|
<property name="holdService" ref="HoldService" />
|
||||||
|
<property name="capabilityService" ref="CapabilityService" />
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="threadCount">
|
||||||
|
<value>${rm.hold.bulk.threadCount}</value>
|
||||||
|
</property>
|
||||||
|
<property name="batchSize">
|
||||||
|
<value>${rm.hold.bulk.batchSize}</value>
|
||||||
|
</property>
|
||||||
|
<property name="maxItems">
|
||||||
|
<value>${rm.hold.bulk.maxItems}</value>
|
||||||
|
</property>
|
||||||
|
<property name="loggingIntervalMs">
|
||||||
|
<value>${rm.hold.bulk.logging.interval.ms}</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="holdBulkMonitor" class="org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkMonitor">
|
||||||
|
<property name="holdProgressCache" ref="holdProgressCache" />
|
||||||
|
<property name="holdProcessRegistry" ref="holdProcessRegistry" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
<bean name="holdProgressCache" factory-bean="cacheFactory" factory-method="createCache">
|
||||||
|
<constructor-arg value="cache.workerRegistryCache" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="holdProcessRegistry" factory-bean="cacheFactory" factory-method="createCache">
|
||||||
|
<constructor-arg value="cache.workerRegistryCache" />
|
||||||
|
</bean>
|
||||||
</beans>
|
</beans>
|
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import org.alfresco.repo.batch.BatchProcessWorkProvider;
|
||||||
|
import org.alfresco.repo.batch.BatchProcessor;
|
||||||
|
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||||
|
import org.alfresco.rest.api.search.impl.SearchMapper;
|
||||||
|
import org.alfresco.rest.api.search.model.Query;
|
||||||
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
|
||||||
|
public abstract class BulkBaseService<T> implements InitializingBean
|
||||||
|
{
|
||||||
|
private static final Log logger = LogFactory.getLog(BulkBaseService.class);
|
||||||
|
|
||||||
|
private ServiceRegistry serviceRegistry;
|
||||||
|
private SearchService searchService;
|
||||||
|
private TransactionService transactionService;
|
||||||
|
private SearchMapper searchMapper;
|
||||||
|
private BulkMonitor<T> bulkMonitor;
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
private int threadCount;
|
||||||
|
private int batchSize;
|
||||||
|
private long maxItems;
|
||||||
|
private int loggingIntervalMs;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception
|
||||||
|
{
|
||||||
|
this.searchService = serviceRegistry.getSearchService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T execute(NodeRef holdRef, BulkOperation bulkOperation)
|
||||||
|
{
|
||||||
|
checkPermissions(holdRef, bulkOperation);
|
||||||
|
|
||||||
|
long totalItems = getTotalItems(bulkOperation.searchQuery());
|
||||||
|
if (maxItems < totalItems)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Too many items to process. Please refine your query.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String processId = UUID.randomUUID().toString();
|
||||||
|
T initBulkStatus = getInitBulkStatus(processId, totalItems);
|
||||||
|
bulkMonitor.updateBulkStatus(initBulkStatus);
|
||||||
|
bulkMonitor.registerProcess(holdRef, processId);
|
||||||
|
BatchProcessWorker<NodeRef> batchProcessWorker = getWorkerProvider(holdRef, bulkOperation);
|
||||||
|
BatchProcessor<NodeRef> batchProcessor = new BatchProcessor<NodeRef>(
|
||||||
|
processId,
|
||||||
|
transactionService.getRetryingTransactionHelper(),
|
||||||
|
getWorkProvider(bulkOperation, totalItems),
|
||||||
|
threadCount,
|
||||||
|
batchSize,
|
||||||
|
applicationEventPublisher,
|
||||||
|
logger,
|
||||||
|
loggingIntervalMs);
|
||||||
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
executor.submit(runBatchProcessor(batchProcessor, batchProcessWorker));
|
||||||
|
return initBulkStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Callable<Void> runBatchProcessor(BatchProcessor<NodeRef> batchProcessor,
|
||||||
|
BatchProcessWorker<NodeRef> batchProcessWorker)
|
||||||
|
{
|
||||||
|
return () -> {
|
||||||
|
TaskScheduler taskScheduler = getTaskScheduler(batchProcessor, bulkMonitor);
|
||||||
|
taskScheduler.schedule(loggingIntervalMs);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
batchProcessor.processLong(batchProcessWorker, true);
|
||||||
|
taskScheduler.runTask();
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
//TODO: handle exception
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
taskScheduler.stopListening();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T getInitBulkStatus(String processId, long totalItems);
|
||||||
|
|
||||||
|
protected abstract TaskScheduler getTaskScheduler(BatchProcessor<NodeRef> batchProcessor, BulkMonitor<T> monitor);
|
||||||
|
|
||||||
|
protected abstract BatchProcessWorkProvider<NodeRef> getWorkProvider(BulkOperation bulkOperation, long totalItems);
|
||||||
|
|
||||||
|
protected abstract BatchProcessWorker<NodeRef> getWorkerProvider(NodeRef nodeRef, BulkOperation bulkOperation);
|
||||||
|
|
||||||
|
protected abstract void checkPermissions(NodeRef holdRef, BulkOperation bulkOperation);
|
||||||
|
|
||||||
|
protected long getTotalItems(Query searchQuery)
|
||||||
|
{
|
||||||
|
SearchParameters searchParams = new SearchParameters();
|
||||||
|
searchMapper.setDefaults(searchParams);
|
||||||
|
searchMapper.fromQuery(searchParams, searchQuery);
|
||||||
|
searchParams.setSkipCount(0);
|
||||||
|
searchParams.setMaxItems(1);
|
||||||
|
return searchService.query(searchParams).getNumberFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
|
||||||
|
{
|
||||||
|
this.applicationEventPublisher = applicationEventPublisher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||||
|
{
|
||||||
|
this.serviceRegistry = serviceRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchService(SearchService searchService)
|
||||||
|
{
|
||||||
|
this.searchService = searchService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionService(TransactionService transactionService)
|
||||||
|
{
|
||||||
|
this.transactionService = transactionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchMapper(SearchMapper searchMapper)
|
||||||
|
{
|
||||||
|
this.searchMapper = searchMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBulkMonitor(BulkMonitor<T> bulkMonitor)
|
||||||
|
{
|
||||||
|
this.bulkMonitor = bulkMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThreadCount(int threadCount)
|
||||||
|
{
|
||||||
|
this.threadCount = threadCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatchSize(int batchSize)
|
||||||
|
{
|
||||||
|
this.batchSize = batchSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxItems(long maxItems)
|
||||||
|
{
|
||||||
|
this.maxItems = maxItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoggingIntervalMs(int loggingIntervalMs)
|
||||||
|
{
|
||||||
|
this.loggingIntervalMs = loggingIntervalMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchMapper getSearchMapper()
|
||||||
|
{
|
||||||
|
return searchMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBatchSize()
|
||||||
|
{
|
||||||
|
return batchSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchService getSearchService()
|
||||||
|
{
|
||||||
|
return searchService;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
public interface BulkMonitor<T>
|
||||||
|
{
|
||||||
|
void updateBulkStatus(T bulkStatus);
|
||||||
|
|
||||||
|
void registerProcess(NodeRef nodeRef, String processId);
|
||||||
|
|
||||||
|
T getBulkStatus(String processName);
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk;
|
||||||
|
|
||||||
|
import org.alfresco.rest.api.search.model.Query;
|
||||||
|
|
||||||
|
public record BulkOperation(Query searchQuery, String operationType)
|
||||||
|
{
|
||||||
|
public BulkOperation
|
||||||
|
{
|
||||||
|
if (operationType == null || searchQuery == null)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Operation type and search query must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk;
|
||||||
|
|
||||||
|
public interface TaskScheduler
|
||||||
|
{
|
||||||
|
void schedule(long msInterval);
|
||||||
|
|
||||||
|
void runTask();
|
||||||
|
|
||||||
|
void stopListening();
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk.hold;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkMonitor;
|
||||||
|
import org.alfresco.repo.cache.SimpleCache;
|
||||||
|
import org.alfresco.rm.rest.api.model.HoldBulkStatus;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
public class HoldBulkMonitor implements BulkMonitor<HoldBulkStatus>
|
||||||
|
{
|
||||||
|
private SimpleCache<String, HoldBulkStatus> holdProgressCache;
|
||||||
|
private SimpleCache<String, List<String>> holdProcessRegistry;
|
||||||
|
|
||||||
|
public void updateBulkStatus(HoldBulkStatus holdBulkStatus)
|
||||||
|
{
|
||||||
|
holdProgressCache.put(holdBulkStatus.processId(), holdBulkStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerProcess(NodeRef holdRef, String processId)
|
||||||
|
{
|
||||||
|
List<String> processIds = Optional.ofNullable(holdProcessRegistry.get(holdRef.getId()))
|
||||||
|
.orElse(new ArrayList<>());
|
||||||
|
processIds.add(processId);
|
||||||
|
holdProcessRegistry.put(holdRef.getId(), processIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HoldBulkStatus getBulkStatus(String processName)
|
||||||
|
{
|
||||||
|
return holdProgressCache.get(processName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HoldBulkStatus> getBatchStatusesForHold(String holdId)
|
||||||
|
{
|
||||||
|
return Optional.ofNullable(holdProcessRegistry.get(holdId))
|
||||||
|
.map(list -> list.stream()
|
||||||
|
.map(this::getBulkStatus)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted(Comparator.comparing(HoldBulkStatus::endTime, Comparator.nullsLast(Comparator.naturalOrder()))
|
||||||
|
.thenComparing(HoldBulkStatus::startTime, Comparator.nullsLast(Comparator.naturalOrder()))
|
||||||
|
.reversed())
|
||||||
|
.toList())
|
||||||
|
.orElse(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHoldProgressCache(
|
||||||
|
SimpleCache<String, HoldBulkStatus> holdProgressCache)
|
||||||
|
{
|
||||||
|
this.holdProgressCache = holdProgressCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHoldProcessRegistry(
|
||||||
|
SimpleCache<String, List<String>> holdProcessRegistry)
|
||||||
|
{
|
||||||
|
this.holdProcessRegistry = holdProcessRegistry;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk.hold;
|
||||||
|
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
|
||||||
|
import org.alfresco.rm.rest.api.model.HoldBulkStatus;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
public interface HoldBulkService
|
||||||
|
{
|
||||||
|
HoldBulkStatus execute(NodeRef holdRef, BulkOperation bulkOperation);
|
||||||
|
}
|
@@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk.hold;
|
||||||
|
|
||||||
|
import static org.alfresco.model.ContentModel.PROP_NAME;
|
||||||
|
import static org.alfresco.rm.rest.api.model.HoldBulkOperationType.ADD;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkBaseService;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkMonitor;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.TaskScheduler;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
|
||||||
|
import org.alfresco.repo.batch.BatchProcessWorkProvider;
|
||||||
|
import org.alfresco.repo.batch.BatchProcessor;
|
||||||
|
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||||
|
import org.alfresco.rest.api.search.impl.SearchMapper;
|
||||||
|
import org.alfresco.rest.api.search.model.Query;
|
||||||
|
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
|
||||||
|
import org.alfresco.rm.rest.api.model.HoldBulkStatus;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
|
import org.springframework.extensions.surf.util.I18NUtil;
|
||||||
|
|
||||||
|
public class HoldBulkServiceImpl extends BulkBaseService<HoldBulkStatus> implements HoldBulkService
|
||||||
|
{
|
||||||
|
private HoldService holdService;
|
||||||
|
private static final String MSG_ERR_ACCESS_DENIED = "permissions.err_access_denied";
|
||||||
|
|
||||||
|
private CapabilityService capabilityService;
|
||||||
|
private PermissionService permissionService;
|
||||||
|
private NodeService nodeService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HoldBulkStatus getInitBulkStatus(String processId, long totalItems)
|
||||||
|
{
|
||||||
|
return new HoldBulkStatus(processId, null, null, 0, 0, totalItems, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TaskScheduler getTaskScheduler(BatchProcessor<NodeRef> batchProcessor,
|
||||||
|
BulkMonitor<HoldBulkStatus> monitor)
|
||||||
|
{
|
||||||
|
return new HoldTaskScheduler(() -> monitor.updateBulkStatus(
|
||||||
|
new HoldBulkStatus(batchProcessor.getProcessName(), batchProcessor.getStartTime(),
|
||||||
|
batchProcessor.getEndTime(), batchProcessor.getSuccessfullyProcessedEntriesLong(),
|
||||||
|
batchProcessor.getTotalErrorsLong(), batchProcessor.getTotalResultsLong(),
|
||||||
|
batchProcessor.getLastError())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BatchProcessWorkProvider<NodeRef> getWorkProvider(BulkOperation bulkOperation, long totalItems)
|
||||||
|
{
|
||||||
|
return new AddToHoldWorkerProvider(new AtomicInteger(0), bulkOperation, totalItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BatchProcessWorker<NodeRef> getWorkerProvider(NodeRef nodeRef, BulkOperation bulkOperation)
|
||||||
|
{
|
||||||
|
if (ADD.name().equals(bulkOperation.operationType()))
|
||||||
|
{
|
||||||
|
return new AddToHoldWorkerBatch(nodeRef);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Unsupported action type when starting the bulk process: " + bulkOperation.operationType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkPermissions(NodeRef holdRef, BulkOperation bulkOperation)
|
||||||
|
{
|
||||||
|
if (!holdService.isHold(holdRef))
|
||||||
|
{
|
||||||
|
final String holdName = (String) nodeService.getProperty(holdRef, PROP_NAME);
|
||||||
|
throw new InvalidArgumentException(I18NUtil.getMessage("rm.hold.not-hold", holdName), null);
|
||||||
|
}
|
||||||
|
if (ADD.name().equals(bulkOperation.operationType()))
|
||||||
|
{
|
||||||
|
if (!AccessStatus.ALLOWED.equals(
|
||||||
|
capabilityService.getCapabilityAccessState(holdRef, RMPermissionModel.ADD_TO_HOLD)) ||
|
||||||
|
permissionService.hasPermission(holdRef, RMPermissionModel.FILING) == AccessStatus.DENIED)
|
||||||
|
{
|
||||||
|
throw new AccessDeniedException(I18NUtil.getMessage(MSG_ERR_ACCESS_DENIED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AddToHoldWorkerBatch implements BatchProcessWorker<NodeRef>
|
||||||
|
{
|
||||||
|
private final NodeRef holdRef;
|
||||||
|
private final String currentUser;
|
||||||
|
|
||||||
|
public AddToHoldWorkerBatch(NodeRef holdRef)
|
||||||
|
{
|
||||||
|
this.holdRef = holdRef;
|
||||||
|
currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier(NodeRef entry)
|
||||||
|
{
|
||||||
|
return entry.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeProcess()
|
||||||
|
{
|
||||||
|
AuthenticationUtil.pushAuthentication();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(NodeRef entry) throws Throwable
|
||||||
|
{
|
||||||
|
AuthenticationUtil.setFullyAuthenticatedUser(currentUser);
|
||||||
|
holdService.addToHold(holdRef, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterProcess()
|
||||||
|
{
|
||||||
|
AuthenticationUtil.popAuthentication();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AddToHoldWorkerProvider implements BatchProcessWorkProvider<NodeRef>
|
||||||
|
{
|
||||||
|
private final AtomicInteger currentNodeNumber;
|
||||||
|
private final Query searchQuery;
|
||||||
|
private final String currentUser;
|
||||||
|
private final long totalItems;
|
||||||
|
|
||||||
|
public AddToHoldWorkerProvider(AtomicInteger currentNodeNumber, BulkOperation bulkOperation, long totalItems)
|
||||||
|
{
|
||||||
|
this.currentNodeNumber = currentNodeNumber;
|
||||||
|
this.searchQuery = bulkOperation.searchQuery();
|
||||||
|
this.totalItems = totalItems;
|
||||||
|
currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalEstimatedWorkSize()
|
||||||
|
{
|
||||||
|
return (int) totalItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTotalEstimatedWorkSizeLong()
|
||||||
|
{
|
||||||
|
return totalItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<NodeRef> getNextWork()
|
||||||
|
{
|
||||||
|
AuthenticationUtil.pushAuthentication();
|
||||||
|
AuthenticationUtil.setFullyAuthenticatedUser(currentUser);
|
||||||
|
SearchParameters searchParams = getNextPageParameters();
|
||||||
|
ResultSet result = getSearchService().query(searchParams);
|
||||||
|
if (result.getNodeRefs().isEmpty())
|
||||||
|
{
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
AuthenticationUtil.popAuthentication();
|
||||||
|
currentNodeNumber.addAndGet(getBatchSize());
|
||||||
|
return result.getNodeRefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchParameters getNextPageParameters()
|
||||||
|
{
|
||||||
|
SearchParameters searchParams = new SearchParameters();
|
||||||
|
SearchMapper searchMapper = getSearchMapper();
|
||||||
|
searchMapper.setDefaults(searchParams);
|
||||||
|
searchMapper.fromQuery(searchParams, searchQuery);
|
||||||
|
searchParams.setSkipCount(currentNodeNumber.get());
|
||||||
|
searchParams.setMaxItems(getBatchSize());
|
||||||
|
searchParams.addSort("@" + ContentModel.PROP_CREATED, true);
|
||||||
|
return searchParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHoldService(HoldService holdService)
|
||||||
|
{
|
||||||
|
this.holdService = holdService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCapabilityService(CapabilityService capabilityService)
|
||||||
|
{
|
||||||
|
this.capabilityService = capabilityService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissionService(PermissionService permissionService)
|
||||||
|
{
|
||||||
|
this.permissionService = permissionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeService(NodeService nodeService)
|
||||||
|
{
|
||||||
|
this.nodeService = nodeService;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk.hold;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.TaskScheduler;
|
||||||
|
|
||||||
|
public class HoldTaskScheduler implements TaskScheduler
|
||||||
|
{
|
||||||
|
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
private ScheduledFuture<?> scheduledTask;
|
||||||
|
private Runnable task;
|
||||||
|
|
||||||
|
public HoldTaskScheduler(Runnable task)
|
||||||
|
{
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void schedule(long loggingInterval)
|
||||||
|
{
|
||||||
|
scheduledTask = executor.scheduleAtFixedRate(task, loggingInterval, loggingInterval, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTask()
|
||||||
|
{
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopListening()
|
||||||
|
{
|
||||||
|
scheduledTask.cancel(false);
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.rm.rest.api.holds;
|
||||||
|
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
|
||||||
|
import static org.alfresco.util.ParameterCheck.mandatory;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkMonitor;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||||
|
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
|
||||||
|
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
|
||||||
|
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
|
||||||
|
import org.alfresco.rest.framework.resource.RelationshipResource;
|
||||||
|
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
|
||||||
|
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||||
|
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||||
|
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
|
||||||
|
import org.alfresco.rm.rest.api.model.HoldBulkStatus;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
|
import org.springframework.extensions.surf.util.I18NUtil;
|
||||||
|
|
||||||
|
@RelationshipResource(name = "bulk-statuses", entityResource = HoldsEntityResource.class, title = "Bulk statuses of a hold")
|
||||||
|
public class HoldsBulkStatusesRelation
|
||||||
|
implements RelationshipResourceAction.Read<HoldBulkStatus>, RelationshipResourceAction.ReadById<HoldBulkStatus>
|
||||||
|
{
|
||||||
|
private HoldBulkMonitor holdBulkMonitor;
|
||||||
|
private FilePlanComponentsApiUtils apiUtils;
|
||||||
|
private PermissionService permissionService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CollectionWithPagingInfo<HoldBulkStatus> readAll(String holdId, Parameters parameters)
|
||||||
|
{
|
||||||
|
// validate parameters
|
||||||
|
checkNotBlank("holdId", holdId);
|
||||||
|
mandatory("parameters", parameters);
|
||||||
|
|
||||||
|
NodeRef holdRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
|
||||||
|
|
||||||
|
checkReadPermissions(holdRef);
|
||||||
|
|
||||||
|
List<HoldBulkStatus> statuses = holdBulkMonitor.getBatchStatusesForHold(holdId);
|
||||||
|
List<HoldBulkStatus> page = statuses.stream()
|
||||||
|
.skip(parameters.getPaging().getSkipCount())
|
||||||
|
.limit(parameters.getPaging().getMaxItems())
|
||||||
|
.collect(Collectors.toCollection(LinkedList::new));
|
||||||
|
int totalItems = statuses.size();
|
||||||
|
boolean hasMore = parameters.getPaging().getSkipCount() + parameters.getPaging().getMaxItems() < totalItems;
|
||||||
|
return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, hasMore, totalItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HoldBulkStatus readById(String holdId, String processId, Parameters parameters)
|
||||||
|
throws RelationshipResourceNotFoundException
|
||||||
|
{
|
||||||
|
checkNotBlank("processId", processId);
|
||||||
|
mandatory("parameters", parameters);
|
||||||
|
|
||||||
|
NodeRef holdRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
|
||||||
|
|
||||||
|
checkReadPermissions(holdRef);
|
||||||
|
|
||||||
|
return Optional.ofNullable(holdBulkMonitor.getBulkStatus(processId)).orElseThrow(() -> new EntityNotFoundException(processId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkReadPermissions(NodeRef holdRef)
|
||||||
|
{
|
||||||
|
if (permissionService.hasReadPermission(holdRef) == AccessStatus.DENIED)
|
||||||
|
{
|
||||||
|
throw new PermissionDeniedException(I18NUtil.getMessage("permissions.err_access_denied"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHoldBulkMonitor(HoldBulkMonitor holdBulkMonitor)
|
||||||
|
{
|
||||||
|
this.holdBulkMonitor = holdBulkMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
|
||||||
|
{
|
||||||
|
this.apiUtils = apiUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissionService(PermissionService permissionService)
|
||||||
|
{
|
||||||
|
this.permissionService = permissionService;
|
||||||
|
}
|
||||||
|
}
|
@@ -30,6 +30,8 @@ import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.c
|
|||||||
import static org.alfresco.util.ParameterCheck.mandatory;
|
import static org.alfresco.util.ParameterCheck.mandatory;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkService;
|
||||||
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
|
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
|
||||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
@@ -42,6 +44,8 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
|
|||||||
import org.alfresco.rest.framework.webscripts.WithResponse;
|
import org.alfresco.rest.framework.webscripts.WithResponse;
|
||||||
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
|
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
|
||||||
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
|
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
|
||||||
|
import org.alfresco.rm.rest.api.model.HoldBulkOperation;
|
||||||
|
import org.alfresco.rm.rest.api.model.HoldBulkStatus;
|
||||||
import org.alfresco.rm.rest.api.model.HoldDeletionReason;
|
import org.alfresco.rm.rest.api.model.HoldDeletionReason;
|
||||||
import org.alfresco.rm.rest.api.model.HoldModel;
|
import org.alfresco.rm.rest.api.model.HoldModel;
|
||||||
import org.alfresco.service.cmr.model.FileFolderService;
|
import org.alfresco.service.cmr.model.FileFolderService;
|
||||||
@@ -68,6 +72,7 @@ public class HoldsEntityResource implements
|
|||||||
private ApiNodesModelFactory nodesModelFactory;
|
private ApiNodesModelFactory nodesModelFactory;
|
||||||
private HoldService holdService;
|
private HoldService holdService;
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
|
private HoldBulkService holdBulkService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception
|
public void afterPropertiesSet() throws Exception
|
||||||
@@ -157,6 +162,22 @@ public class HoldsEntityResource implements
|
|||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation("bulk")
|
||||||
|
@WebApiDescription(title = "Start the hold bulk operation",
|
||||||
|
successStatus = HttpServletResponse.SC_ACCEPTED)
|
||||||
|
public HoldBulkStatus bulk(String holdId, HoldBulkOperation holdBulkOperation, Parameters parameters,
|
||||||
|
WithResponse withResponse)
|
||||||
|
{
|
||||||
|
// validate parameters
|
||||||
|
checkNotBlank("holdId", holdId);
|
||||||
|
mandatory("parameters", parameters);
|
||||||
|
|
||||||
|
NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
|
||||||
|
|
||||||
|
return holdBulkService.execute(parentNodeRef,
|
||||||
|
new BulkOperation(holdBulkOperation.query(), holdBulkOperation.op().name()));
|
||||||
|
}
|
||||||
|
|
||||||
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
|
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
|
||||||
{
|
{
|
||||||
this.apiUtils = apiUtils;
|
this.apiUtils = apiUtils;
|
||||||
@@ -181,4 +202,9 @@ public class HoldsEntityResource implements
|
|||||||
{
|
{
|
||||||
this.transactionService = transactionService;
|
this.transactionService = transactionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHoldBulkService(HoldBulkService holdBulkService)
|
||||||
|
{
|
||||||
|
this.holdBulkService = holdBulkService;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.rm.rest.api.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import org.alfresco.rest.api.search.model.Query;
|
||||||
|
|
||||||
|
public record HoldBulkOperation(@JsonProperty(required = true) Query query, @JsonProperty(required = true) HoldBulkOperationType op) {}
|
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.rm.rest.api.model;
|
||||||
|
|
||||||
|
public enum HoldBulkOperationType
|
||||||
|
{
|
||||||
|
ADD
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.rm.rest.api.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public record HoldBulkStatus(String processId, Date startTime, Date endTime, long itemsProcessed, long errorsCount,
|
||||||
|
long totalItems, String lastError) implements Serializable
|
||||||
|
{
|
||||||
|
public enum Status
|
||||||
|
{
|
||||||
|
PENDING("PENDING"),
|
||||||
|
IN_PROGRESS("IN PROGRESS"),
|
||||||
|
DONE("DONE");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
Status(String value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus()
|
||||||
|
{
|
||||||
|
if (startTime == null && endTime == null)
|
||||||
|
{
|
||||||
|
return Status.PENDING.getValue();
|
||||||
|
}
|
||||||
|
else if (startTime != null && endTime == null)
|
||||||
|
{
|
||||||
|
return Status.IN_PROGRESS.getValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Status.DONE.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPercentageProcessed()
|
||||||
|
{
|
||||||
|
return itemsProcessed <= totalItems ? NumberFormat.getPercentInstance().format(
|
||||||
|
totalItems == 0 ? 1.0F : (float) itemsProcessed / totalItems) : "Unknown";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2024 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco 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
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.bulk.hold;
|
||||||
|
|
||||||
|
import org.alfresco.repo.cache.SimpleCache;
|
||||||
|
import org.alfresco.rm.rest.api.model.HoldBulkStatus;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class HoldBulkMonitorTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SimpleCache<String, HoldBulkStatus> holdProgressCache;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SimpleCache<String, List<String>> holdProcessRegistry;
|
||||||
|
|
||||||
|
private HoldBulkMonitor holdBulkMonitor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.openMocks(this);
|
||||||
|
holdBulkMonitor = new HoldBulkMonitor();
|
||||||
|
holdBulkMonitor.setHoldProgressCache(holdProgressCache);
|
||||||
|
holdBulkMonitor.setHoldProcessRegistry(holdProcessRegistry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBatchStatusesForHoldReturnsEmptyListWhenNoProcesses() {
|
||||||
|
when(holdProcessRegistry.get("holdId")).thenReturn(null);
|
||||||
|
assertEquals(Collections.emptyList(), holdBulkMonitor.getBatchStatusesForHold("holdId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBatchStatusesForHoldReturnsSortedStatuses() {
|
||||||
|
HoldBulkStatus status1 = new HoldBulkStatus(null, new Date(1000), new Date(2000), 0L, 0L, 0L, null);
|
||||||
|
HoldBulkStatus status2 = new HoldBulkStatus(null, new Date(3000), null, 0L, 0L, 0L, null);
|
||||||
|
HoldBulkStatus status3 = new HoldBulkStatus(null, new Date(4000), null, 0L, 0L, 0L, null);
|
||||||
|
HoldBulkStatus status4 = new HoldBulkStatus(null, new Date(500), new Date(800), 0L, 0L, 0L, null);
|
||||||
|
HoldBulkStatus status5 = new HoldBulkStatus(null, null, null, 0L, 0L, 0L, null);
|
||||||
|
|
||||||
|
|
||||||
|
when(holdProcessRegistry.get("holdId")).thenReturn(Arrays.asList("process1", "process2", "process3", "process4", "process5"));
|
||||||
|
when(holdProgressCache.get("process1")).thenReturn(status1);
|
||||||
|
when(holdProgressCache.get("process2")).thenReturn(status2);
|
||||||
|
when(holdProgressCache.get("process3")).thenReturn(status3);
|
||||||
|
when(holdProgressCache.get("process4")).thenReturn(status4);
|
||||||
|
when(holdProgressCache.get("process5")).thenReturn(status5);
|
||||||
|
|
||||||
|
assertEquals(Arrays.asList(status5, status3, status2, status1, status4), holdBulkMonitor.getBatchStatusesForHold("holdId"));
|
||||||
|
}
|
||||||
|
}
|
@@ -2314,6 +2314,112 @@ paths:
|
|||||||
description: Unexpected error
|
description: Unexpected error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Error'
|
$ref: '#/definitions/Error'
|
||||||
|
'/holds/{holdId}/bulk-statuses':
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- holds
|
||||||
|
operationId: bulkStatuses
|
||||||
|
summary: Get bulk statuses
|
||||||
|
description: |
|
||||||
|
Gets bulk statuses for hold with id **holdId**.
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/parameters/holdIdParam'
|
||||||
|
- $ref: '#/parameters/skipCountParam'
|
||||||
|
- $ref: '#/parameters/maxItemsParam'
|
||||||
|
responses:
|
||||||
|
'202':
|
||||||
|
description: Successful response
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/HoldBulkStatusPaging'
|
||||||
|
'400':
|
||||||
|
description: |
|
||||||
|
Invalid parameter: **holdId** is not a valid format
|
||||||
|
'401':
|
||||||
|
description: Authentication failed
|
||||||
|
'403':
|
||||||
|
description: Current user does not have permission to read **holdId**
|
||||||
|
'404':
|
||||||
|
description: "**holdId** does not exist"
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error'
|
||||||
|
'/holds/{holdId}/bulk-statuses/{processId}':
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- holds
|
||||||
|
operationId: bulkStatus
|
||||||
|
summary: Get the bulk status
|
||||||
|
description: |
|
||||||
|
Gets the bulk status specified by **processId** for **holdId**.
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/parameters/holdIdParam'
|
||||||
|
- $ref: '#/parameters/processId'
|
||||||
|
responses:
|
||||||
|
'202':
|
||||||
|
description: Successful response
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/HoldBulkStatus'
|
||||||
|
'400':
|
||||||
|
description: |
|
||||||
|
Invalid parameter: **holdId** or **processId** is not a valid format
|
||||||
|
'401':
|
||||||
|
description: Authentication failed
|
||||||
|
'403':
|
||||||
|
description: Current user does not have permission to read **holdId**
|
||||||
|
'404':
|
||||||
|
description: "**holdId** or **processId** does not exist"
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error'
|
||||||
|
'/holds/{holdId}/bulk':
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- holds
|
||||||
|
operationId: holdBulk
|
||||||
|
summary: Start the hold bulk process
|
||||||
|
description: |
|
||||||
|
Start the asynchronous bulk process of a hold with id **holdId** based on search query results.
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
For example, the following JSON body start the bulk process to add search query results
|
||||||
|
as children of a hold.
|
||||||
|
|
||||||
|
{
|
||||||
|
"query": {
|
||||||
|
"query": "SITE:swsdp and TYPE:content",
|
||||||
|
"language": "afts"
|
||||||
|
},
|
||||||
|
"op": "ADD"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/parameters/holdIdParam'
|
||||||
|
- in: body
|
||||||
|
name: holdBulkOperation
|
||||||
|
description: Bulk operation.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/HoldBulkOperation'
|
||||||
|
responses:
|
||||||
|
'202':
|
||||||
|
description: Successful response
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/HoldBulkStatus'
|
||||||
|
'400':
|
||||||
|
description: |
|
||||||
|
Invalid parameter: **holdId** is not a valid format or **HoldBulkOperation** is not valid
|
||||||
|
'401':
|
||||||
|
description: Authentication failed
|
||||||
|
'403':
|
||||||
|
description: Current user does not have permission to start the bulk process of **holdId**
|
||||||
|
'404':
|
||||||
|
description: "**holdId** does not exist"
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error'
|
||||||
'/holds/{holdId}/delete':
|
'/holds/{holdId}/delete':
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -2862,6 +2968,12 @@ parameters:
|
|||||||
description: The identifier of a child of a hold.
|
description: The identifier of a child of a hold.
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
processId:
|
||||||
|
name: processId
|
||||||
|
in: path
|
||||||
|
description: The identifier of a bulk process.
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
## Record
|
## Record
|
||||||
recordIdParam:
|
recordIdParam:
|
||||||
name: recordId
|
name: recordId
|
||||||
@@ -4018,6 +4130,84 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
reason:
|
reason:
|
||||||
type: string
|
type: string
|
||||||
|
RequestQuery:
|
||||||
|
description: Query.
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- query
|
||||||
|
properties:
|
||||||
|
language:
|
||||||
|
description: The query language in which the query is written.
|
||||||
|
type: string
|
||||||
|
default: afts
|
||||||
|
enum:
|
||||||
|
- afts
|
||||||
|
- lucene
|
||||||
|
- cmis
|
||||||
|
userQuery:
|
||||||
|
description: The exact search request typed in by the user
|
||||||
|
type: string
|
||||||
|
query:
|
||||||
|
description: The query which may have been generated in some way from the userQuery
|
||||||
|
type: string
|
||||||
|
HoldBulkOperation:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
query:
|
||||||
|
$ref: '#/definitions/RequestQuery'
|
||||||
|
op:
|
||||||
|
description: The query language in which the query is written.
|
||||||
|
type: string
|
||||||
|
default: ADD
|
||||||
|
enum:
|
||||||
|
- ADD
|
||||||
|
HoldBulkStatus:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
processId:
|
||||||
|
type: string
|
||||||
|
startTime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
endTime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
itemsProcessed:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
errorsCount:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
totalItems:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
lastError:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- PENDING
|
||||||
|
- IN PROGRESS
|
||||||
|
- DONE
|
||||||
|
HoldBulkStatusEntry:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- entry
|
||||||
|
properties:
|
||||||
|
entry:
|
||||||
|
$ref: '#/definitions/HoldBulkStatus'
|
||||||
|
HoldBulkStatusPaging:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
list:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
pagination:
|
||||||
|
$ref: '#/definitions/Pagination'
|
||||||
|
entries:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/HoldBulkStatusEntry'
|
||||||
##
|
##
|
||||||
RequestBodyFile:
|
RequestBodyFile:
|
||||||
type: object
|
type: object
|
||||||
|
@@ -710,3 +710,5 @@ cache.ldapInitialDirContextCache.backup-count=1
|
|||||||
cache.ldapInitialDirContextCache.eviction-policy=NONE
|
cache.ldapInitialDirContextCache.eviction-policy=NONE
|
||||||
cache.ldapInitialDirContextCache.merge-policy=com.hazelcast.spi.merge.LatestUpdateMergePolicy
|
cache.ldapInitialDirContextCache.merge-policy=com.hazelcast.spi.merge.LatestUpdateMergePolicy
|
||||||
cache.ldapInitialDirContextCache.readBackupData=false
|
cache.ldapInitialDirContextCache.readBackupData=false
|
||||||
|
|
||||||
|
cache.workerRegistryCache.type=fully-distributed
|
Reference in New Issue
Block a user