Merge V3.2 To HEAD

17894 : Merge from NEILM to V3.2



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18233 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2010-01-21 17:48:10 +00:00
parent ac8529fc24
commit 41e574f3d5
11 changed files with 600 additions and 29 deletions

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.action;
import java.util.Comparator;
/**
* This class is the base filter class for asynchronous actions. These filters are used in identifying
* 'equivalent' actions in the asynchronous action execution service. By registering
* a subclass of this type, all actions of a given action-definition-name that are still pending
* (i.e. currently executing or in the queue awaiting execution) will be compared to any new action
* and if they are equal (as determined by the compare implementation defined herein) the newly
* submitted action will not be added to the queue and will be dropped.
*
* Concrete subclasses can be implemented and then dependency-injected using the spring-bean
* baseActionFilter as their parent.
*
* @author Neil McErlean
*/
public abstract class AbstractAsynchronousActionFilter implements Comparator<OngoingAsyncAction>
{
private String name;
private String actionDefinitionName;
private AsynchronousActionExecutionQueueImpl asynchronousActionExecutionQueue;
/**
* Gets the name of this comparator.
* @return
*/
public String getName()
{
return this.name;
}
/**
* Sets the name of this comparator.
* @param name
*/
public void setName(String name)
{
this.name = name;
}
/**
* Gets the action definition name against which this comparator is registered.
* @return
*/
public String getActionDefinitionName()
{
return this.actionDefinitionName;
}
public void setActionDefinitionName(String actionDefinitionName)
{
this.actionDefinitionName = actionDefinitionName;
}
public void setAsynchronousActionExecutionQueue(
AsynchronousActionExecutionQueueImpl asynchronousActionExecutionQueue)
{
this.asynchronousActionExecutionQueue = asynchronousActionExecutionQueue;
}
public void init()
{
this.asynchronousActionExecutionQueue.registerActionFilter(this);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,6 +25,8 @@
package org.alfresco.repo.action;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -35,6 +37,7 @@ import org.alfresco.repo.action.evaluator.InCategoryEvaluator;
import org.alfresco.repo.action.evaluator.NoConditionEvaluator;
import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation;
import org.alfresco.repo.action.executer.ActionExecuter;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
import org.alfresco.repo.action.executer.CheckInActionExecuter;
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
@@ -42,6 +45,7 @@ import org.alfresco.repo.action.executer.CompositeActionExecuter;
import org.alfresco.repo.action.executer.MoveActionExecuter;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionCondition;
@@ -49,6 +53,7 @@ import org.alfresco.service.cmr.action.ActionConditionDefinition;
import org.alfresco.service.cmr.action.ActionDefinition;
import org.alfresco.service.cmr.action.CompositeAction;
import org.alfresco.service.cmr.action.CompositeActionCondition;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -56,6 +61,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.BaseAlfrescoSpringTest;
/**
@@ -69,12 +75,28 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
private NodeRef nodeRef;
private NodeRef folder;
private RetryingTransactionHelper transactionHelper;
@Override
protected String[] getConfigLocations()
{
String[] existingConfigLocations = ApplicationContextHelper.CONFIG_LOCATIONS;
List<String> locations = Arrays.asList(existingConfigLocations);
List<String> mutableLocationsList = new ArrayList<String>(locations);
mutableLocationsList.add("classpath:org/alfresco/repo/action/test-action-services-context.xml");
String[] result = mutableLocationsList.toArray(new String[mutableLocationsList.size()]);
return (String[]) result;
}
@Override
protected void onSetUpInTransaction() throws Exception
{
super.onSetUpInTransaction();
this.transactionHelper = (RetryingTransactionHelper)this.applicationContext.getBean("retryingTransactionHelper");
// Create the node used for tests
this.nodeRef = this.nodeService.createNode(
this.rootNodeRef,
@@ -761,6 +783,85 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
* Test asynchronous actions
*/
/**
* This test checks that a series of "equivalent" actions submitted for asynchronous execution
* will be correctly filtered so that no 2 equivalent actions are executed at the same time.
*/
public void testAsyncLongRunningActionsFilter()
{
setComplete();
endTransaction();
final SleepActionExecuter sleepAction = (SleepActionExecuter)applicationContext.getBean("sleep-action");
assertNotNull(sleepAction);
final int actionSubmissonCount = 4; // Rather arbitrary count.
for (int i = 0; i < actionSubmissonCount; i ++)
{
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
Action action = actionService.createAction(SleepActionExecuter.NAME);
action.setExecuteAsynchronously(true);
actionService.executeAction(action, nodeRef);
return null;
}
});
}
// Wait long enough for previous action(s) to have executed and then submit another
try
{
Thread.sleep(sleepAction.getSleepMs() * actionSubmissonCount + 1000); // Enough time for all actions and an extra second for luck.
}
catch (InterruptedException ignored)
{
// intentionally empty
}
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
Action action = actionService.createAction(SleepActionExecuter.NAME);
action.setExecuteAsynchronously(true);
actionService.executeAction(action, nodeRef);
return null;
}
});
try
{
Thread.sleep(sleepAction.getSleepMs() + 2000); // Enough time for latest action and an extra 2 seconds for luck.
}
catch (InterruptedException ignored)
{
// intentionally empty
}
int sleepTime = 0; // Do not sleep during execution as the Action itself sleeps.
int maxTries = 1;
postAsyncActionTest(
this.transactionService,
sleepTime,
maxTries,
new AsyncTest()
{
public String executeTest()
{
final int expectedResult = 2;
int actualResult = sleepAction.getTimesExecuted();
return actualResult == expectedResult ? null : "Expected timesExecuted " + expectedResult + " was " + actualResult;
};
});
}
/**
* Test asynchronous execute action
*/
@@ -786,10 +887,10 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
10,
new AsyncTest()
{
public boolean executeTest()
public String executeTest()
{
return (
finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_CLASSIFIABLE));
boolean result = finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_CLASSIFIABLE);
return result ? null : "Expected aspect Classifiable";
};
});
}
@@ -828,11 +929,11 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
10,
new AsyncTest()
{
public boolean executeTest()
public String executeTest()
{
return (
finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_VERSIONABLE) &&
finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_LOCKABLE));
boolean result = finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_VERSIONABLE) &&
finalNodeService.hasAspect(finalNodeRef, ContentModel.ASPECT_LOCKABLE);
return result ? null : "Expected aspects Versionable & Lockable";
};
});
}
@@ -872,8 +973,8 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
try
{
int tries = 0;
boolean done = false;
while (done == false && tries < maxTries)
String errorMsg = null;
while (errorMsg == null && tries < maxTries)
{
try
{
@@ -883,16 +984,16 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
// Sleep for a bit
Thread.sleep(sleepTime);
done = (transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionCallback<Boolean>()
errorMsg = (transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionCallback<String>()
{
public Boolean execute()
public String execute()
{
// See if the action has been performed
boolean done = test.executeTest();
String done = test.executeTest();
return done;
}
})).booleanValue();
}));
}
catch (InterruptedException e)
{
@@ -901,9 +1002,9 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
}
}
if (done == false)
if (errorMsg != null)
{
throw new RuntimeException("Asynchronous action was not executed.");
throw new RuntimeException("Asynchronous action was not executed. " + errorMsg);
}
}
catch (Throwable exception)
@@ -918,7 +1019,11 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
*/
public interface AsyncTest
{
boolean executeTest();
/**
*
* @return <code>null</code> if the test succeeded, else an error message for use in JUnit report.
*/
String executeTest();
}
/** ===================================================================================
@@ -1009,10 +1114,10 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
10,
new AsyncTest()
{
public boolean executeTest()
public String executeTest()
{
return (
ActionServiceImplTest.this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_CLASSIFIABLE));
boolean result = ActionServiceImplTest.this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_CLASSIFIABLE);
return result == true ? null : "Expected aspect Classifiable";
};
});
@@ -1040,4 +1145,68 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
});
}
/**
* This class is only used during JUnit testing.
*
* @author Neil Mc Erlean
*/
public static class SleepActionFilter extends AbstractAsynchronousActionFilter
{
public int compare(OngoingAsyncAction sae1, OngoingAsyncAction sae2)
{
// Sleep actions are always equivalent.
return 0;
}
}
/**
* This class is only intended for use in JUnit tests.
*
* @author Neil McErlean.
*/
public static class SleepActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "sleep-action";
private int sleepMs;
private int timesExecuted = 0;
private void incrementTimesExecutedCount() {timesExecuted++;}
public int getTimesExecuted() {return timesExecuted;}
public int getSleepMs()
{
return sleepMs;
}
public void setSleepMs(int sleepMs)
{
this.sleepMs = sleepMs;
}
/**
* Add parameter definitions
*/
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
// Intentionally empty
}
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
try
{
Thread.sleep(sleepMs);
}
catch (InterruptedException ignored)
{
// Intentionally empty
}
finally
{
incrementTimesExecutedCount();
}
}
}
}

View File

@@ -25,8 +25,13 @@
package org.alfresco.repo.action;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.Map.Entry;
import java.util.concurrent.ThreadPoolExecutor;
import org.alfresco.error.StackTraceUtil;
@@ -47,6 +52,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.EqualsHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -64,7 +70,17 @@ public class AsynchronousActionExecutionQueueImpl implements AsynchronousActionE
private TransactionService transactionService;
private AuthenticationContext authenticationContext;
private PolicyComponent policyComponent;
private NodeService nodeService;
private Map<String, AbstractAsynchronousActionFilter>
actionFilters = new HashMap<String, AbstractAsynchronousActionFilter>();
private NodeService nodeService;
/**
* We keep a record of ongoing asynchronous actions (this includes those being executed and
* those that are in the queue).
* This needs to be thread-safe - hence the Vector.
*/
List<OngoingAsyncAction> ongoingActions = new Vector<OngoingAsyncAction>();
// Policy delegates
private ClassPolicyDelegate<OnAsyncActionExecute> onAsyncActionExecuteDelegate;
@@ -169,6 +185,37 @@ public class AsynchronousActionExecutionQueueImpl implements AsynchronousActionE
return qnames;
}
/**
* This method registers an action filter, which can be used to prevent unwanted or unnecessary
* asynchronous actions from being scheduled for execution.
*
* @param filter the filter implementation.
*/
public void registerActionFilter(AbstractAsynchronousActionFilter filter)
{
String filterName = filter.getName();
if (logger.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Registered asynchronous action filter ")
.append(filter.getName()).append(" for action ")
.append(filter.getActionDefinitionName());
logger.debug(msg.toString());
}
AbstractAsynchronousActionFilter existingFilter = actionFilters.get(filterName);
if (logger.isDebugEnabled() && existingFilter != null)
{
StringBuilder msg = new StringBuilder();
msg.append("This replaces previous filter ")
.append(existingFilter.getName());
logger.debug(msg.toString());
}
this.actionFilters.put(filter.getName(), filter);
}
/**
* {@inheritDoc}
*/
@@ -185,6 +232,22 @@ public class AsynchronousActionExecutionQueueImpl implements AsynchronousActionE
public void executeAction(RuntimeActionService actionService, Action action, NodeRef actionedUponNodeRef,
boolean checkConditions, Set<String> actionChain, NodeRef actionExecutionHistoryNodeRef)
{
if (logger.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Received request to execute async action ").append(action.getActionDefinitionName())
.append(" on ").append(actionedUponNodeRef);
logger.debug(msg.toString());
msg = new StringBuilder();
msg.append("ThreadPool's active count = ").append(this.threadPoolExecutor.getActiveCount());
logger.debug(msg.toString());
msg = new StringBuilder();
msg.append("ThreadPool's queue size = ").append(this.threadPoolExecutor.getQueue().size());
logger.debug(msg.toString());
}
Set<RuleServiceImpl.ExecutedRuleData> executedRules =
(Set<RuleServiceImpl.ExecutedRuleData>) AlfrescoTransactionSupport.getResource("RuleServiceImpl.ExecutedRules");
Runnable runnable = new ActionExecutionWrapper(
@@ -195,7 +258,60 @@ public class AsynchronousActionExecutionQueueImpl implements AsynchronousActionE
actionExecutionHistoryNodeRef,
actionChain,
executedRules);
threadPoolExecutor.execute(runnable);
// Consider whether this action should be filtered out by one of the registered filters.
boolean newActionShouldBeFilteredOut = false;
OngoingAsyncAction nodeBeingNewlyActioned = new OngoingAsyncAction(actionedUponNodeRef, action);
for (Entry<String, AbstractAsynchronousActionFilter> entry : actionFilters.entrySet())
{
AbstractAsynchronousActionFilter comparator = entry.getValue();
String actionDefinitionName = comparator.getActionDefinitionName();
if (actionDefinitionName.equals(action.getActionDefinitionName()) == false)
{
// We're only interested in registered actions with the same name as this one.
continue;
}
else
{
// Now we've found a registered action that matches the current one.
// So we'll go through the actions that are ongoing and consider them for matches with this one.
for (OngoingAsyncAction ongoingAction : this.ongoingActions)
{
if (comparator.compare(ongoingAction, nodeBeingNewlyActioned) == 0)
{
newActionShouldBeFilteredOut = true;
break;
}
}
}
}
if (newActionShouldBeFilteredOut)
{
if (logger.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Dropping action ").append(action).append(" as equivalent is ongoing.");
logger.debug(msg.toString());
}
return;
}
else
{
if (logger.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Executing action ").append(action);
logger.debug(msg.toString());
}
// Queue it and do it.
ongoingActions.add(nodeBeingNewlyActioned);
threadPoolExecutor.execute(runnable);
}
// Done
if (logger.isDebugEnabled())
{
@@ -214,8 +330,19 @@ public class AsynchronousActionExecutionQueueImpl implements AsynchronousActionE
}
}
private void handleAsyncActionIsCompleted(NodeRef n, Action action) {
if (logger.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
msg.append("Completed action ").append(action);
logger.debug(msg.toString());
}
OngoingAsyncAction ongoing = new OngoingAsyncAction(n, action);
ongoingActions.remove(ongoing);
}
/**
* Tansaction listener used to invoke callback policies
* Transaction listener used to invoke callback policies
*/
public class CallbackTransactionListener extends TransactionListenerAdapter
{
@@ -384,6 +511,7 @@ public class AsynchronousActionExecutionQueueImpl implements AsynchronousActionE
{
logger.error("Failed to execute asynchronous action: " + action, exception);
}
}
handleAsyncActionIsCompleted(actionedUponNodeRef, action);
}
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.action;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This filter class is used to identify equivalent create-thumbnail actions.
* Two create-thumbnail actions are considered equivalent if they are on the same NodeRef and
* if they have the same thumbnail-name parameter.
*
* @author Neil McErlean
*/
public class CreateThumbnailActionFilter extends AbstractAsynchronousActionFilter
{
private static final String PARAM_THUMBNAIL_NAME = "thumbnail-name";
public int compare(OngoingAsyncAction nodeAction1, OngoingAsyncAction nodeAction2)
{
NodeRef n1 = nodeAction1.getNodeRef();
NodeRef n2 = nodeAction2.getNodeRef();
if (n1.equals(n2) == false)
{
return -1;
}
else
{
String thName1 = (String)nodeAction1.getAction().getParameterValue(PARAM_THUMBNAIL_NAME);
String thName2 = (String)nodeAction2.getAction().getParameterValue(PARAM_THUMBNAIL_NAME);
return thName1.compareTo(thName2);
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.action;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.EqualsHelper;
/**
* This class represents an ongoing asynchronous action.
*/
public class OngoingAsyncAction
{
private final NodeRef node;
private final Action action;
public OngoingAsyncAction(NodeRef node, Action action)
{
this.node = node;
this.action = action;
}
public NodeRef getNodeRef()
{
return node;
}
public Action getAction()
{
return action;
}
@Override
public boolean equals(Object otherObj)
{
if (otherObj == null || !otherObj.getClass().equals(this.getClass()))
{
return false;
}
OngoingAsyncAction otherNodeBeingActioned = (OngoingAsyncAction)otherObj;
return EqualsHelper.nullSafeEquals(this.node, otherNodeBeingActioned.node) &&
EqualsHelper.nullSafeEquals(this.action.getActionDefinitionName(), otherNodeBeingActioned.action.getActionDefinitionName());
}
@Override
public int hashCode() {
return this.node.hashCode() + 7 * this.action.getActionDefinitionName().hashCode();
}
@Override
public String toString()
{
StringBuilder msg = new StringBuilder();
msg.append(node).append(", ").append(action.getActionDefinitionName());
return msg.toString();
}
}

View File

@@ -0,0 +1,22 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="sleep-action" class="org.alfresco.repo.action.ActionServiceImplTest$SleepActionExecuter" parent="action-executer">
<property name="publicAction">
<value>false</value>
</property>
<property name="sleepMs">
<value>1000</value>
</property>
</bean>
<bean id="sleepActionFilter" class="org.alfresco.repo.action.ActionServiceImplTest$SleepActionFilter" parent="baseActionFilter">
<property name="name">
<value>preventMultipleSleepActions</value>
</property>
<property name="actionDefinitionName">
<value>sleep-action</value>
</property>
</bean>
</beans>

View File

@@ -171,7 +171,7 @@ public abstract class AbstractContentTransformer2 extends ContentTransformerHelp
// Make sure that this transformation gets set back i.t.o. time taken.
// This will ensure that transformers that compete for the same transformation
// will be prejudiced against transformers that tend to fail
recordTime(10000); // 10 seconds, i.e. rubbish
recordTime(60 * 1000); // 1 minute, i.e. rubbish
throw new ContentIOException("Content conversion failed: \n" +
" reader: " + reader + "\n" +

View File

@@ -295,11 +295,12 @@ public class RuleServiceCoverageTest extends TestCase
100,
new AsyncTest()
{
public boolean executeTest()
public String executeTest()
{
return RuleServiceCoverageTest.this.nodeService.hasAspect(
boolean result = RuleServiceCoverageTest.this.nodeService.hasAspect(
newNodeRef,
ContentModel.ASPECT_VERSIONABLE);
return result ? "" : "Expected aspect Versionable";
};
});
}