Tag: acp

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.