Space Cleanup: Rules, Space Templates and Action!

Sometimes you may want a work space or directory to be deleted when it becomes empty. For instance, you may have a temporary directory to share files for review or collaboration. The workspace or folder will remain available until the reviews and collaborations have been completed and the documents filed or moved into their designated spaces. Once the documents are moved out of the workspace, it would be best practice to remove the folder to keep your document management system clean, organized and manageable.

One of the many ways to achieve this behavior in Alfresco, would be to add a custom Action, and attach it to a rule. Another way, may be to add a behavior policy on the directories that need to be monitored and removed. Alternatively, you may write a cron job to routinely purge unused folders. Or maybe, you may regularly remind your users to clean up after themselves. In this article however, we’ll examine how to achieve this functionality in Alfresco, via Rules, Space Templates and Actions.

The Alfresco Services used for this are:

The inherited classes and interfaces are:

When this action is included as part of a rule, with criterions set to listen for items leaving or being deleted from the target directory, it will execute to delete the target directory.

Alfresco_»_Folder_RulesThe Custom ActionExecuter in this example was named rmdir and bound to the class  RemoveFolderExecuter as defined in the class example below:

 

public class RemoveFolderExecuter extends ActionExecuterAbstractBase {
public static final String NAME = "rmdir";

public static final String PARAM_FORCE_DELETION = "force-deletion";
public static final String PARAM_THROW_EXCEPTION_ON_FAILURE = "exception-failure";
/**
* Used to exclude directories from where this action will execute. such as
* template folder.
*/
public static final String PARAM_EXCEPTION_LIST = "exception-list";
private FileFolderService fileFolderService;
private NodeService nodeService;
private RuleService ruleService;
Logger logger = Logger.getLogger(RemoveFolderExecuter.class);

@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {

Boolean forceDeletion = (Boolean) action
.getParameterValue(PARAM_FORCE_DELETION);
Boolean exceptionFailure = (Boolean) action
.getParameterValue(PARAM_THROW_EXCEPTION_ON_FAILURE);
String exceptionList = (String) action
.getParameterValue(PARAM_EXCEPTION_LIST);
if (logger.isDebugEnabled()) {
logger.debug("Actioned Upon: " + actionedUponNodeRef);
logger.debug("Force Deletion: " + forceDeletion);
logger.debug("exceptionFailure: " + exceptionFailure);
logger.debug("exceptionList: " + exceptionList);
}

NodeRef owningNodeRef = ruleService.getOwningNodeRef(action);

if (exceptionList == null
|| exceptionList.indexOf(owningNodeRef.toString()) < 0) {
if (forceDeletion != null && forceDeletion)
fileFolderService.delete(owningNodeRef);
else {
if (logger.isDebugEnabled()) {
for (FileInfo child : fileFolderService
.listFiles(owningNodeRef)) {
logger.debug("Children: " + child.getNodeRef() + " - "
+ child.getName());
}
}
int childrenCount = fileFolderService.listFiles(owningNodeRef)
.size();
logger.debug("Children Count for: " + owningNodeRef + " : "
+ childrenCount);
if (childrenCount > 0) {
String msg = "Deletion failed.Folder {" + owningNodeRef
+ "} is not empty ";
if (exceptionFailure != null && exceptionFailure)
throw new RemoveFolderException(msg);
logger.debug(msg);
} else {
fileFolderService.delete(owningNodeRef);
}
}
} else {
logger.debug("Skipping the deletion of " + owningNodeRef);
}
}

@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList) {
paramList.add(new ParameterDefinitionImpl(PARAM_FORCE_DELETION,
DataTypeDefinition.BOOLEAN, true,
getParamDisplayLabel(PARAM_FORCE_DELETION)));
paramList.add(new ParameterDefinitionImpl(
PARAM_THROW_EXCEPTION_ON_FAILURE, DataTypeDefinition.BOOLEAN,
true, getParamDisplayLabel(PARAM_THROW_EXCEPTION_ON_FAILURE)));
}

public FileFolderService getFileFolderService() {
return fileFolderService;
}

public void setFileFolderService(FileFolderService fileFolderService) {
this.fileFolderService = fileFolderService;
}

public NodeService getNodeService() {
return nodeService;
}

public void setNodeService(NodeService nodeService) {
this.nodeService = nodeService;
}

public RuleService getRuleService() {
return ruleService;
}

public void setRuleService(RuleService ruleService) {
this.ruleService = ruleService;
}

}

 

This class will then be wired into the Spring IOC bean configuration as follows:

<bean id="rmdir" class="org.alfresco.consulting.actions.RemoveFolderExecuter" parent="action-executer">
<property name="fileFolderService" ref="fileFolderService" />
<property name="nodeService" ref="nodeService" />
<property name="ruleService" ref="ruleService" />
</bean>

 

A working example of this functionality can be found in the Alfresco workflow upload functionality module. In this referenced project, the Action and rule will be automatically added to the Alfresco Templates directory; so that folders based on this templated behavior can be easily created.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: