Alfresco has a category hierarchy that can be used to categorize content. Unlike tags, which are not in a hierarchy and can be created by anyone, categories must be managed by an administrator. But even an administrator cannot move a category from one parent to another through the user interface. When it is time to reorganize your categories, how do you do it?
It’s actually pretty easy to do this with code. Your first thought might be, “Well, a category is a node and server-side JavaScript can work with nodes, so I’ll just write a quick script to do the move,” and who could blame you–that’s a well-reasoned line of thinking. But if you look at the source for the current JavaScript API ScriptNode object’s “move” method, you’ll see that it assumes that the association it is creating is “cm:contains”. Categories are associated with an association called “cm:subcategories”, not “cm:contains”. So, at least in this release, JavaScript can’t help us.
Luckily, Alfresco’s Java API is up to the task. When you call the NodeService’s moveNode method you have full control over the new relationship that gets created.
For stuff like this it is often handy to whip up a little Java-backed web script. All the web script needs is the source node reference that needs to be moved and a target node reference to move the source node reference to. Here’s the class with debug and parameter checking removed:
public class MoveCategory extends DeclarativeWebScript { // Dependencies private NodeService nodeService; @Override protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) { final String sourceNodeRefString = req.getParameter("sourceNodeRef"); final String targetNodeRefString = req.getParameter("targetNodeRef"); // snag the nodes NodeRef sourceNodeRef = new NodeRef(sourceNodeRefString); String sourceName = (String) nodeService.getProperty( sourceNodeRef, ContentModel.PROP_NAME); NodeRef targetNodeRef = new NodeRef(targetNodeRefString); String targetName = (String) nodeService.getProperty( targetNodeRef, ContentModel.PROP_NAME); // move the source node to the target nodeService.moveNode(sourceNodeRef, targetNodeRef, ContentModel.ASSOC_SUBCATEGORIES, QName.createQName( NamespaceService.CONTENT_MODEL_1_0_URI, sourceName)); // set up the model Map<String, Object> model = new HashMap<String, Object>(); model.put("sourceNodeRef", sourceNodeRefString); model.put("sourceName", sourceName); model.put("targetNodeRef", targetNodeRefString); model.put("targetName", targetName); return model; } public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } }
If you need to see how to wire up the web script with Spring configuration, or you want to see the rest of the web script files (like the descriptor & view), you can take a look at this zipped up Eclipse project.
I should mention that in my web script descriptor, I configured the web script to require an authenticated user, but I set it to run as admin. That gives non-admin users the ability to move categories around using this web script. You may or may not want to do that.
Also, because this is just an example, I’m using the zip overlay method of deployment. For production, you should be using AMPs.
For more Java-backed web script examples, see this wiki page. And if you would prefer to use Maven to develop your Java-backed web scripts, take a look at this project on Google Code.