cancel
Showing results for 
Search instead for 
Did you mean: 

ACP Import with UUID Binding Specified

analyzediz
Champ in-the-making
Champ in-the-making
There does currently appear to be a way of specifying the uuid binding value for the Importer Action.

I'm thinking there's no way to do this other than extending the ImporterActionExecuter class and allowing for that parameter to be passed in. In this class the ImporterService's importView() method is being invoked but the action is passing in a null value which means that the service will, by default, use a UUID Binding value of CREATE_NEW.

Anyone out there solved this?

Thanks
4 REPLIES 4

jm_pascal
Star Contributor
Star Contributor
Have you seen this article :
http://ecmarchitect.com/archives/2008/10/27/859

Maybe it can help you to resolve your problem…

tommorris
Champ in-the-making
Champ in-the-making
I glanced at the ecmarchitect article, and it looks like Jeff's approach (very helpfully pointed-out by jm.pascal!) will work.
It's what I've done too. Although I extended the class instead of copying it:

package com.ixxus.projectname.alfresco.actions.importer;

import java.io.File;

import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.executer.ImporterActionExecuter;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.importer.ACPImportPackageHandler;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.view.ImporterBinding;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ACPImportActionExecuter extends ImporterActionExecuter
{   
    private static final Log log = LogFactory.getLog(ACPImportActionExecuter.class);
    public static final String NAME = "custom-import";
    public static final String PARAM_ENCODING = "encoding";
    public static final String PARAM_DESTINATION_FOLDER = "destination";
    private static final String TEMP_FILE_PREFIX = "alf";
    private static final String TEMP_FILE_SUFFIX_ACP = ".acp";
    private ImporterBinding.UUID_BINDING uuidBinding;
    private ImporterService importerService;
    private NodeService nodeService;
    private ContentService contentService;

   public void setImporterService(ImporterService importerService) {
      this.importerService = importerService;
   }

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

   public void setContentService(ContentService contentService) {
      this.contentService = contentService;
   }

    /**
     * @see org.alfresco.repo.action.executer.ActionExecuter#execute(org.alfresco.repo.ref.NodeRef, org.alfresco.repo.ref.NodeRef)
     */
   @Override
    public void executeImpl(Action ruleAction, NodeRef actionedUponNodeRef) {
        log.error("actionedUponNodeRef:" + actionedUponNodeRef);
        if (this.nodeService.exists(actionedUponNodeRef) == true)
        {
           // The node being passed in should be an Alfresco content package
           ContentReader reader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
           if (reader != null)
           {
               NodeRef importDest = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
               log.error("importDest:" + importDest + " actionedUponNodeRef:" + actionedUponNodeRef);
               if (MimetypeMap.MIMETYPE_ACP.equals(reader.getMimetype()))
               {
                   // perform an import of an Alfresco ACP file (special format ZIP structure)
                   File zipFile = null;
                   try
                   {
                       // unfortunately a ZIP file can not be read directly from an input stream so we have to create
                       // a temporary file first
                       zipFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ACP);
                       reader.getContent(zipFile);
                      
                       ACPImportPackageHandler importHandler = new ACPImportPackageHandler(zipFile,
                             (String)ruleAction.getParameterValue(PARAM_ENCODING));
                     
                       this.importerService.importView(importHandler, new Location(importDest), getBinding(), null);
                   }
                   finally
                   {
                      // now the import is done, delete the temporary file
                      if (zipFile != null)
                      {
                         zipFile.delete();
                      }
                   }
               }
           }
        }
    }

   private ImporterBinding getBinding() {
      ImporterBinding binding = new ImporterBinding() {
         public boolean allowReferenceWithinTransaction() {
            return false;
         }
         public QName[] getExcludedClasses() {
            return null;
         }
         public UUID_BINDING getUUIDBinding() {
            return uuidBinding;
         }
         public String getValue(String key) {
            return null;
         }
      };    
      
      // Uses UPDATE_EXISTING as usage of REPLACE_EXISTING removes child nodes if these are not sent over in the export.
      uuidBinding = ImporterBinding.UUID_BINDING.UPDATE_EXISTING;
      return binding;
   }
}

with the bean definition of:

    <bean id="custom-import" class="com.ixxus.projectname.alfresco.actions.importer.ACPImportActionExecuter" 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>
    </bean>

Tom
http://www.ixxus.com

analyzediz
Champ in-the-making
Champ in-the-making
Thank you so much jm.pascal and Tom!  I had seen this article a long while back but didn't remember.

So I opted to extend the ImportActionExecuter with a slight variation, I inject the UUID Binding type from the Spring bean definition, that way it's a bit more flexible. I seem to run into some issues when I run it though.  I'm currently working with Alfresco Share, so I create an ACP file from the site level (/company_home/sites/mySite). The ACP XML shows that it exports the mySite space and all the other folders underneath that.

When I try to import the ACP into a separate Alfresco repository, I get the following error:


20:17:22,740 User:admin ERROR [ui.common.Utils] Failed to create content due to error: 04100002 Failed to execute script 'workspace://SpacesStore/fe58573b-95fe-4b63-a6bd-39867247d86a': Failed to import package at line 27; column 20 due to error: Duplicate child name not allowed: mySite
org.alfresco.scripts.ScriptException: 04100002 Failed to execute script 'workspace://SpacesStore/fe58573b-95fe-4b63-a6bd-39867247d86a': Failed to import package at line 27; column 20 due to error: Duplicate child name not allowed: mySite
   at org.alfresco.repo.jscript.RhinoScriptProcessor.execute(RhinoScriptProcessor.java:228)
   at org.alfresco.repo.processor.ScriptServiceImpl.executeScript(ScriptServiceImpl.java:187)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
   at org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor.invoke(AlwaysProceedMethodInterceptor.java:40)
….

The UUIDBinding that I use is: UPDATE_EXISTING. From what I read in the Alfresco Wiki it should override the content item if it exists and create a new one if it doesn't exist. Now I'm not sure how this affects spaces/folders. It appears to be failing at the root node in the ACP. It works just fine if the ACP is imported into an empty space.

Have you guys seen this error before?  Thanks a lot for you time.

tommorris
Champ in-the-making
Champ in-the-making
Well, you're using the correct binding.

It can overwrite existing nodes (folder nodes or content nodes), as long as the nodes share the same UUID. If you've exported the ACP from one repo and are then importing into another repo, you should clear the destination of the same content the first time - but subsequent attempts at overwriting should be fine, since they'll share the same UUID.