AnsweredAssumed Answered

Adding a New 'Finalize' Document Action

Question asked by smayuri on Jul 24, 2018

Hi,

I am trying to create a custom document action called 'Finalize' in Alfresco. I've attempted the following procedure,

Step 1: Created a new AMP Project

            The first step is to create a new project using the Alfresco Maven SDK.

            mvn archetype:generate -Dfilter=org.alfresco:

Step 2 : Created a custom content model xml fiile

              scModel.xml is created in following directory and I have attached scModel.xml file in the attachments :                ~/add_action_tutorial/content-tutorial/content-tutorial-platform-jar/src/main/resources/alfresco/module/content-tutorial-platform-jar/model

 

Step 3 : Registered the new model with a spring bean

             The file is named service-context.xml created in following directory and attached here for your reference,

             ~/add_action_tutorial/content-tutorial/content-tutorial-platform-jar/src/main/resources/alfresco/module/content-tutorial-platform-jar/context

 

Step 4 :

           Run :  mvn install

           Maven downloaded everything it needs to run Alfresco in an embedded Tomcat server along with my custom content model.

 

Step 5 :

            Configured the custom content model in Alfresco Share,

            Created a custom share configuration file : A module called "content-repo-share-jar" was added to my project when I created the content-tutorial project using the Alfresco SDK using the "all-in-one" archetype.Created an empty XML file called "share-config-custom.xml" in:

        ~/add_action_tutorial/content-tutorial/content-tutorial-share-jar/src/main/resources/META-INF

 

  1. Edited the share-config-custom.xml file and added the following:

  2. <alfresco-config>    
    <!-- Document Library config section -->   
    <config evaluator="string-compare" condition="DocumentLibrary">   
    </config>
    </alfresco-config>

    Added an aspects element as a child of the config element to identify the aspects that are visible, addable, and removeable:

    <aspects>
        <!-- Aspects that a user can see -->
        <visible>
            <aspect name="sc:webable" />
            <aspect name="sc:productRelated" />           
        </visible>

        <!-- Aspects that a user can add. Same as "visible" if left empty -->
        <addable>
        </addable>

        <!-- Aspects that a user can remove. Same as "visible" if left empty -->
        <removeable>
        </removeable>
    </aspects>
  3. That takes care of aspects. Configured the types. Added a types element as a sibling to the aspects element I added with the following content:

    <types>
        <type name="cm:content">
            <subtype name="sc:doc" />
            <subtype name="sc:whitepaper" />
        </type>
        <type name="sc:doc">
            <subtype name="sc:whitepaper" />
        </type>
    </types>

Step 6 : Tested the changes

              ./run.sh

            Started a Tomcat server with the Alfresco WAR and Share WARS deployed along with repository tier AMP and Share tier AMP.

 

Step 7 : Action Project Organisation

            I created action-tutorial project just like content-tutorial, actions tutorial project depends on the content tutorial project. When I launched the actions-tutorial project in the embedded Tomcat server I want the AMPs from the content tutorial to be installed, so those need to go into the pom.xml file as module dependencies:

<platformModules>
...SNIP...
<moduleDependency>
    <groupId>com.someco</groupId>
    <artifactId>content-tutorial-platform-jar</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <type>amp</type>
</moduleDependency>
...SNIP...
</platformModules>
<shareModules>
...SNIP...
    <moduleDependency>
        <groupId>com.someco</groupId>
        <artifactId>content-tutorial-share-jar</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>amp</type>
    </moduleDependency>
...SNIP...
</shareModules>

The actions tutorial actually has a compile-time dependency on that project. So, I added the dependency to the pom.xml file of actions-tutorial-platform-jar:

<dependencies>
    <dependency>
        <groupId>com.someco</groupId>
        <artifactId>content-tutorial-platform-jar</artifactId>
        <version>1.0-SNAPSHOT</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Step 7 :

   Add "Finalize" action 

  •  Added Action configuration with in share-config-custom.xml

   Action configuration goes under “actions” section of “DocLibActions” config,

 

<action id="document-finalize" type="javascript" icon="tag"label="actions.document.finalize">
   <param name="function">onActionFormDialog</param>
   <!-- Additional parameters for onFormDialog function  -->
   <param name="itemKind">action</param>
   <param name="itemId">doc-finalize</param>
   <param name="mode">create</param>
   <param name="destination">{node.nodeRef}</param>
   <param name="successMessage">message.tagging.success</param>
   <param name="failureMessage">message.tagging.failure</param>
</action>

 

  • For showing it on front end added it into two action groups as follow.

<actionGroup id="document-browse">      
     <action index="370" id="document-finalize" />
</actionGroup>
<actionGroup id="document-details">
     <action index="400" id="document-finalize" />
</actionGroup>
  • Form config for action form

<config evaluator="string-compare" condition="doc-finalize">   
    <forms>
      <form>
         <field-visibility>
            <show id="tagname"/>
         </field-visibility>
         <appearance>
            <field id="tagname" label-id="doc-finalize.field.tagname">
               <control template="/org/alfresco/components/form/controls/textarea.ftl" />            
            </field>
         </appearance>
      </form>
   </forms>
</config>
  • Added Icon for action : Copy tag-16.jpg icon from tomcat\webapps\share\components\documentlibrary\images to tomcat\webapps\share\components\documentlibrary\actions

 

  • Implemented action bean

    package com.someco.action.executer;
    import java.io.Serializable;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import org.alfresco.repo.action.ParameterDefinitionImpl;
    import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
    import org.alfresco.service.cmr.action.Action;
    import org.alfresco.service.cmr.action.ParameterDefinition;
    import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
    import org.alfresco.service.cmr.repository.NodeRef;
    import org.alfresco.service.cmr.repository.NodeService;
    import org.alfresco.service.namespace.QName;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.alfresco.service.cmr.lock.LockService;
    import org.alfresco.service.cmr.lock.LockStatus;
    import org.alfresco.model.ContentModel;
    import com.someco.model.SomeCoModel;
    public class DocumentFinalizeActionExecuter extends ActionExecuterAbstractBase {

    //public final static String NAME = "set-web-flag";
    public final static String PARAM_TAG_NAME = "doc-tagging";

    /** The NodeService to be used by the bean */
    protected NodeService nodeService;

    public LockService lockService;

    private static Log logger = LogFactory.getLog(DocumentFinalizeActionExecuter.class);

    @Override
    protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
    String tagname = (String) action.getParameterValue(PARAM_TAG_NAME);
    // set the sc:isActive property to true
    // set the sc:published property to now
    Map<QName, Serializable> properties = nodeService.getProperties(actionedUponNodeRef);
    //properties.put(QName.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL, SomeCoModel.PROP_IS_ACTIVE), activeFlag);

    // if the aspect has already been added, set the properties
    if (nodeService.hasAspect(actionedUponNodeRef,
    QName.createQName(
    SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
    SomeCoModel.ASPECT_SC_WEBABLE))) {
    if (logger.isDebugEnabled()) logger.debug("Node has aspect");
    nodeService.setProperties(actionedUponNodeRef, properties);
    } else {
    // otherwise, add the aspect and set the properties
    if (logger.isDebugEnabled()) logger.debug("Node does not have aspect");
    nodeService.addAspect(actionedUponNodeRef, QName.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL, SomeCoModel.ASPECT_SC_WEBABLE), properties);


    if (logger.isDebugEnabled()) logger.debug("Ran document tagging action");
    nodeService.
    if (isNodeLocked(nodeService,lockService)) {
    //finalize menu will disable
    //We want to write business logic of finalizing a document here
    }

    }
    @Override
    protected void addParameterDefinitions(List<ParameterDefinition> paramList) {
    paramList.add(
    new ParameterDefinitionImpl( // Create a new parameter definition to add to the list
    PARAM_TAG_NAME, // The name used to identify the parameter
    DataTypeDefinition.TEXT, // The parameter value type
    false, // Indicates whether the parameter is mandatory
    getParamDisplayLabel(PARAM_TAG_NAME))); // The parameters display label

    }
    /**
    * @param nodeService The NodeService to set.
    */
    public void setNodeService(NodeService nodeService) {
    this.nodeService = nodeService;
    }

    /** 
    * Return whether a Node is currently locked
    * @param node The Node wrapper to test against
    * @param lockService The LockService to use
    * @return whether a Node is currently locked
    */
    public static Boolean isNodeLocked(NodeService nodeService,LockService lockService){
    Boolean locked=Boolean.FALSE;
    if (nodeService.hasAspect(ContentModel.ASPECT_LOCKABLE)) {
    LockStatus lockStatus=lockService.getLockStatus(nodeService.getNodeRef());
    if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER) {
    locked=Boolean.TRUE;
    }
    }
    return locked;
    }
    }

 

  • Registered Action Bean

We need to register above bean within spring for that adds entry in the context file service-context.xml and place it under action-tutorial-platform-jar 's context folder 

<bean id="doc-tagging" class="com.someco.action.executer.DocumentFinalizeActionExecuter" parent="action-executer">
   <property name="nodeService">
      <ref bean="NodeService"/>
   </property>
</bean>

What I wanted to do is,

Finalization of a Document: If a document or a design or anything is considered as complete and nobody should be allowed to add any more, it could be declared as final thereby not allowing anyone to actually delete the document. For this I need customize "finalize" document action.

So that I wanted to implement LockService interface of alfresco source code in DocumentFinalizeActionExecuter to check whether the document is locked or not and according to that I will write the business logic on finalize action but in very first step of implementing the LockService Interface of alfresco is giving me an error,

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project actions-tutorial-platform-jar: Compilation failure: Compilation failure.

I have attached the Log files,

  1. WithLockServiceImplement.log : Trying to implement LockService Interface from alfresco source code.

  2. WithoutImplementingLockService.log : Wrote a customized function in DocumentFinalizeActionExecuter and trying to use LockService's functions in it.  

Outcomes