mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merge remote-tracking branch 'origin/merge-2.5/MNT-18793_to_2.5.x' into merge-2.6/MNT-18793
This commit is contained in:
@@ -42,6 +42,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
|
|||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.search.ResultSet;
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
import org.alfresco.service.cmr.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
@@ -122,7 +123,7 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute
|
|||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append("TYPE:\"rma:dispositionAction\" + ");
|
sb.append("TYPE:\"rma:dispositionAction\" AND ");
|
||||||
sb.append("(@rma\\:dispositionAction:(");
|
sb.append("(@rma\\:dispositionAction:(");
|
||||||
|
|
||||||
boolean bFirst = true;
|
boolean bFirst = true;
|
||||||
@@ -164,68 +165,32 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute
|
|||||||
|
|
||||||
if (dispositionActions != null && !dispositionActions.isEmpty())
|
if (dispositionActions != null && !dispositionActions.isEmpty())
|
||||||
{
|
{
|
||||||
// execute search
|
boolean hasMore = true;
|
||||||
ResultSet results = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
int skipCount = 0;
|
||||||
SearchService.LANGUAGE_FTS_ALFRESCO, getQuery());
|
while(hasMore)
|
||||||
List<NodeRef> resultNodes = results.getNodeRefs();
|
|
||||||
results.close();
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
logger.debug("Processing " + resultNodes.size() + " nodes");
|
SearchParameters params = new SearchParameters();
|
||||||
}
|
params.addStore(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||||
|
params.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO);
|
||||||
|
params.setQuery(getQuery());
|
||||||
|
params.setSkipCount(skipCount);
|
||||||
|
|
||||||
// process search results
|
// execute search
|
||||||
for (NodeRef node : resultNodes)
|
ResultSet results = searchService.query(params);
|
||||||
{
|
List<NodeRef> resultNodes = results.getNodeRefs();
|
||||||
final NodeRef currentNode = node;
|
hasMore = results.hasMore();
|
||||||
|
skipCount += resultNodes.size(); // increase by page size
|
||||||
|
results.close();
|
||||||
|
|
||||||
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>()
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
public Boolean execute()
|
logger.debug("Processing " + resultNodes.size() + " nodes");
|
||||||
{
|
}
|
||||||
final String dispAction = (String) nodeService.getProperty(currentNode,
|
|
||||||
RecordsManagementModel.PROP_DISPOSITION_ACTION);
|
|
||||||
|
|
||||||
// Run disposition action
|
// process search results
|
||||||
if (dispAction != null && dispositionActions.contains(dispAction))
|
for (NodeRef node : resultNodes)
|
||||||
{
|
|
||||||
ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode);
|
|
||||||
if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION))
|
|
||||||
{
|
|
||||||
Map<String, Serializable> props = new HashMap<String, Serializable>(1);
|
|
||||||
props.put(RMDispositionActionExecuterAbstractBase.PARAM_NO_ERROR_CHECK,
|
|
||||||
Boolean.FALSE);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// execute disposition action
|
|
||||||
recordsManagementActionService.executeRecordsManagementAction(
|
|
||||||
parent.getParentRef(), dispAction, props);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Processed action: " + dispAction + "on" + parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (AlfrescoRuntimeException exception)
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// if exists
|
|
||||||
if (nodeService.exists(currentNode))
|
|
||||||
{
|
{
|
||||||
retryingTransactionHelper.doInTransaction(processTranCB);
|
executeAction(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,6 +206,62 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method that executes a disposition action
|
||||||
|
*
|
||||||
|
* @param actionNode - the disposition action to execute
|
||||||
|
*/
|
||||||
|
private void executeAction(final NodeRef actionNode)
|
||||||
|
{
|
||||||
|
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>()
|
||||||
|
{
|
||||||
|
public Boolean execute()
|
||||||
|
{
|
||||||
|
final String dispAction = (String) nodeService.getProperty(actionNode,
|
||||||
|
RecordsManagementModel.PROP_DISPOSITION_ACTION);
|
||||||
|
|
||||||
|
// Run disposition action
|
||||||
|
if (dispAction != null && dispositionActions.contains(dispAction))
|
||||||
|
{
|
||||||
|
ChildAssociationRef parent = nodeService.getPrimaryParent(actionNode);
|
||||||
|
if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION))
|
||||||
|
{
|
||||||
|
Map<String, Serializable> props = new HashMap<String, Serializable>(1);
|
||||||
|
props.put(RMDispositionActionExecuterAbstractBase.PARAM_NO_ERROR_CHECK,
|
||||||
|
Boolean.FALSE);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// execute disposition action
|
||||||
|
recordsManagementActionService.executeRecordsManagementAction(
|
||||||
|
parent.getParentRef(), dispAction, props);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Processed action: " + dispAction + "on" + parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (AlfrescoRuntimeException exception)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// if exists
|
||||||
|
if (nodeService.exists(actionNode))
|
||||||
|
{
|
||||||
|
retryingTransactionHelper.doInTransaction(processTranCB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public PersonService getPersonService()
|
public PersonService getPersonService()
|
||||||
{
|
{
|
||||||
return personService;
|
return personService;
|
||||||
|
@@ -29,17 +29,19 @@ package org.alfresco.module.org_alfresco_module_rm.job;
|
|||||||
|
|
||||||
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.generateQName;
|
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.generateQName;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyMap;
|
import static org.mockito.Matchers.anyMap;
|
||||||
import static org.mockito.Matchers.anyString;
|
|
||||||
import static org.mockito.Matchers.contains;
|
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -48,13 +50,15 @@ import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
|
|||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
|
||||||
import org.alfresco.service.cmr.search.ResultSet;
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
import org.alfresco.service.cmr.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposition lifecycle job execution unit test.
|
* Disposition lifecycle job execution unit test.
|
||||||
@@ -92,7 +96,8 @@ public class DispositionLifecycleJobExecuterUnitTest extends BaseUnitTest
|
|||||||
executer.setDispositionActions(dispositionActions);
|
executer.setDispositionActions(dispositionActions);
|
||||||
|
|
||||||
// setup interactions
|
// setup interactions
|
||||||
doReturn(mockedResultSet).when(mockedSearchService).query(eq(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE), eq(SearchService.LANGUAGE_FTS_ALFRESCO), anyString());
|
doReturn(mockedResultSet).when(mockedSearchService).query(any(SearchParameters.class));
|
||||||
|
when(mockedResultSet.hasMore()).thenReturn(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,7 +105,9 @@ public class DispositionLifecycleJobExecuterUnitTest extends BaseUnitTest
|
|||||||
*/
|
*/
|
||||||
private void verifyQuery()
|
private void verifyQuery()
|
||||||
{
|
{
|
||||||
verify(mockedSearchService, times(1)).query(eq(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE), eq(SearchService.LANGUAGE_FTS_ALFRESCO), contains(QUERY));
|
ArgumentCaptor<SearchParameters> paramsCaptor = ArgumentCaptor.forClass(SearchParameters.class);
|
||||||
|
verify(mockedSearchService, times(1)).query(paramsCaptor.capture());
|
||||||
|
assertTrue(paramsCaptor.getValue().getQuery().contains(QUERY));
|
||||||
verify(mockedResultSet, times(1)).getNodeRefs();
|
verify(mockedResultSet, times(1)).getNodeRefs();
|
||||||
verify(mockedResultSet, times(1)).close();
|
verify(mockedResultSet, times(1)).close();
|
||||||
}
|
}
|
||||||
@@ -249,7 +256,64 @@ public class DispositionLifecycleJobExecuterUnitTest extends BaseUnitTest
|
|||||||
{
|
{
|
||||||
String actual = executer.getQuery();
|
String actual = executer.getQuery();
|
||||||
|
|
||||||
String expected = "TYPE:\"rma:dispositionAction\" + (@rma\\:dispositionAction:(\"cutoff\" OR \"retain\")) AND ISUNSET:\"rma:dispositionActionCompletedAt\" AND ( @rma\\:dispositionEventsEligible:true OR @rma\\:dispositionAsOf:[MIN TO NOW] ) ";
|
String expected = "TYPE:\"rma:dispositionAction\" AND " +
|
||||||
|
"(@rma\\:dispositionAction:(\"cutoff\" OR \"retain\")) " +
|
||||||
|
"AND ISUNSET:\"rma:dispositionActionCompletedAt\" " +
|
||||||
|
"AND ( @rma\\:dispositionEventsEligible:true OR @rma\\:dispositionAsOf:[MIN TO NOW] ) ";
|
||||||
|
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the maximum page of elements for search service is 2
|
||||||
|
* and search service finds more than one page of elements
|
||||||
|
* When the job executer runs
|
||||||
|
* Then the executer retrieves both pages and iterates all elements
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPagination()
|
||||||
|
{
|
||||||
|
final NodeRef node1 = generateNodeRef();
|
||||||
|
final NodeRef node2 = generateNodeRef();
|
||||||
|
final NodeRef node3 = generateNodeRef();
|
||||||
|
final NodeRef node4 = generateNodeRef();
|
||||||
|
|
||||||
|
// mock the search service to return the right page
|
||||||
|
when(mockedSearchService.query(any(SearchParameters.class))).thenAnswer(
|
||||||
|
new Answer<ResultSet>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public ResultSet answer(InvocationOnMock invocation)
|
||||||
|
{
|
||||||
|
SearchParameters params = invocation.getArgumentAt(0, SearchParameters.class);
|
||||||
|
if (params.getSkipCount() == 0)
|
||||||
|
{
|
||||||
|
// mock first page
|
||||||
|
ResultSet result1 = mock(ResultSet.class);
|
||||||
|
when(result1.getNodeRefs()).thenReturn(Arrays.asList(node1, node2));
|
||||||
|
when(result1.hasMore()).thenReturn(true);
|
||||||
|
return result1;
|
||||||
|
}
|
||||||
|
else if (params.getSkipCount() == 2)
|
||||||
|
{
|
||||||
|
// mock second page
|
||||||
|
ResultSet result2 = mock(ResultSet.class);
|
||||||
|
when(result2.getNodeRefs()).thenReturn(Arrays.asList(node3, node4));
|
||||||
|
when(result2.hasMore()).thenReturn(false);
|
||||||
|
return result2;
|
||||||
|
}
|
||||||
|
throw new IndexOutOfBoundsException("Pagination did not stop after the second page!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// call the service
|
||||||
|
executer.executeImpl();
|
||||||
|
|
||||||
|
// check the loop iterated trough all the elements
|
||||||
|
verify(mockedNodeService).exists(node1);
|
||||||
|
verify(mockedNodeService).exists(node2);
|
||||||
|
verify(mockedNodeService).exists(node3);
|
||||||
|
verify(mockedNodeService).exists(node4);
|
||||||
|
verify(mockedSearchService, times(2)).query(any(SearchParameters.class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user