Tag: actions

Updated tutorial: Creating Custom Actions in Alfresco

I have published an updated version of the Creating Custom Actions in Alfresco tutorial. Similar to the recently updated Working With Custom Content Types in Alfresco tutorial, this version has been updated to match the refactored code which now assumes you are using the Alfresco Maven SDK to produce AMPs and that you are using Alfresco Share as the user interface. I’ve removed all references to Alfresco Explorer.

The Custom Actions tutorial covers:

  • What is an action
  • How to write your own custom action in Java
  • How to invoke the custom action from a rule or from the Alfresco Share UI
  • Configuring an evaluator to hide the UI action when certain conditions are true
  • Configuring an indicator to show an icon in the document library when documents meet certain conditions
  • Writing and executing unit tests with the Alfresco Maven SDK

If you aren’t familiar with the Alfresco Maven SDK and you need help diving in, take a look at this tutorial.

All of the tutorial source code and text for the Alfresco Developer Series of tutorials is on GitHub. Please fork the project, make improvements, and send me pull requests.

Next on the to-be-updated list is the Custom Behaviors tutorial. I expect that to go live sometime next week.

Importing ACP files with the UUID binding

A common way to get files and metadata into and out of the Alfresco repository is to use ACP (Alfresco Content Package) files. People that work with ACP files quickly find out that the out-of-the-box ACP import action will only import a given object once–it won’t update an object if it is already in the repository. By default, the import action tries to create a new object on every import. If a like-named object already exists the import will fail.

There’s a simple fix for this. The underlying API actually supports updating objects by matching on UUID. All you need to do is create your own version of the import action that uses the UUID_BINDING rather than the default.

Here are the steps:

  1. Find the org/alfresco/repo/action/executer/ImporterActionExecuter.java class in the source.
  2. Make a copy of the class. I called mine com.optaros.action.executer.UpdatingImportExecuter.java.
  3. Find the line of code that reads: this.importerService.importView(importHandler, new Location(importDest), null, null);
  4. Change it to: this.importerService.importView(importHandler, new Location(importDest), REPLACE_BINDING, null);
  5. Now add the definition for REPLACE_BINDING which is a private static inner class:
private static ImporterBinding REPLACE_BINDING = new ImporterBinding()
{

    public UUID_BINDING getUUIDBinding()
    {
        return UUID_BINDING.UPDATE_EXISTING;
    }

    public String getValue(String key)
    {
        return null;
    }

    public boolean allowReferenceWithinTransaction()
    {
        return false;
    }

    public QName[] getExcludedClasses()
    {
        return null;
    }

};

As with any action, the last step is to add the Spring configuration:

<bean id="updating-import" class="com.optaros.action.executer.UpdatingImportExecuter" parent="action-executer">
    <property name="importerService">
        <ref bean="ImporterService"/>
    </property>
    <property name="nodeService">
        <ref bean="NodeService"></ref>
    </property>
    <property name="contentService">
        <ref bean="ContentService" />
    </property>
    <property name="mimetypeService">
        <ref bean="mimetypeService"/>
    </property>
    <property name="fileFolderService">
        <ref bean="FileFolderService"/>
    </property>
</bean>

After deploying your changes and restarting the application server you can test the new action. In my case, I wrote a workflow that used JavaScript to execute the export action to export the documents in the workflow. I then simulated an external system operating on the ACP file by writing a quick Perl script to unzip the ACP, inject some metadata into the ACP’s XML manifest, and then zip it back up. At this point the ACP file contains the exported objects (with their associated UUID) and some new metadata. I then trigger the next step in the workflow which, again, uses JavaScript to execute the newly-written Updating Import Action. Unlike the OOTB import, when this one runs Alfresco finds the existing objects based on the incoming UUID’s and instead of trying to create new objects, it updates the old objects with the new metadata in the ACP file. Problem solved.

You can learn more about writing custom Actions on the Alfresco Wiki and in Chapter 4 of the Alfresco Developer Guide available at Packt Publishing or your favorite online book seller.