cancel
Showing results for 
Search instead for 
Did you mean: 

Proper way to implement a custom a taskListener in Activiti?

jpotts
World-Class Innovator
World-Class Innovator
I want to implement a custom taskListener that leverages the ActionService. I have written a Java class that implements TaskListener. The problem I'm having is how to properly inject the dependency and how to refer to the taskListener from the process definition.

I tried creating the following in one of my context files:
<bean id="externalReviewNotification" class="com.someco.bpm.ExternalReviewNotification">
        <property name="actionService">
            <ref bean="ActionService" />
        </property>
</bean>

I've also tried a version that includes "parent="baseJavaDelegate"".

I then refer to the bean from my process using delegateExpression, like this:
<activiti:taskListener event="create" delegateExpression="${externalReviewNotification}"></activiti:taskListener>

That fails with a org.activiti.engine.ActivitiException: Exception while invoking TaskListener: Unknown property used in expression

I think it is because my bean isn't registered with the activiti bean registry, but I'm not sure.

I've tried using a class attribute instead of the delegateExpression attribute. In that case, notify is called, but my dependencies aren't loaded since it isn't using the bean.

I looked at the source to see how the JavaScript taskListener works. It has a getServiceRegistry method. I suppose I could implement that, but I'm wondering if there's a better way?

Jeff
21 REPLIES 21

pero
Champ in-the-making
Champ in-the-making
Sorry, didn't create a JIRA ticket, I meant an Alfresco Support ticket

Ah. Ok then. You let us know when they fix it Smiley Happy

checco
Champ in-the-making
Champ in-the-making
Hi all,
i have found this topic very interesting, i  think that you can help me especially when i read this:
I tried to implement similar thing as you, but using Activiti ServiceTask, and had the same problems as you.

'activiti:class' way worked fine….
because i can't run any Activiti ServiceTask using activiti:class attribute.

Let me explain, my process definition is very simple:

<process id="MySampleServiceTask" name="MySampleServiceTask">
    <startEvent id="alfrescoStartevent1" name="Alfresco start" activiti:formKey="bpm:startTask"></startEvent>
    <serviceTask id="servicetask1" name="Service Task" activiti:class="workflow.sample.serviceTask.HelloWorldServiceTask"></serviceTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" name="" sourceRef="servicetask1" targetRef="endevent1"></sequenceFlow>
    <sequenceFlow id="flow2" name="" sourceRef="alfrescoStartevent1" targetRef="servicetask1"></sequenceFlow>
  </process>

and the HelloWorldServiceTask is even simpler:

package workflow.sample.serviceTask;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

public class HelloWorldServiceTask implements JavaDelegate {

   public HelloWorldServiceTask() {
      System.out.println("HelloWorldServiceTask created");
   }

   @Override
   public void execute(DelegateExecution arg0) throws Exception {
      System.out.println("Hello Wolrd!");
   }

}
I have put my HelloWorldServiceTask class in a jar in the folder $TOMCAT_HOME/shared/lib/
Started Alfresco and deployed process definition using Activiti Workflow Console
But when i try to start the workflow from  Alfresco Share web application it doesn't work: the workflow doesn't start and a pupup is opened with the message 'Impossible to start workflow'.
I have try  to set the logging level to debug (log4j.logger.org.alfresco.repo.workflow=debug) to have more information but nothing is logged.

Do you have any idea what i'm doing wrong? I missing some configuration?
How can i have a more detailed error message?

Thanks,
Francesco

checco
Champ in-the-making
Champ in-the-making
I have partially resolved my problem. I have Used Alfresco workflow console (http://localhost:8080/alfresco/faces/jsp/admin/workflow-console.jsp) to start my process and a ClassNotfoundException was raised so i have moved my jar with my classes in $TOMCAT_HOME/webapps/alfresco/WEB-INF/lib.

Now when i try to start a new instance of the process the HelloWorldServiceTask is created and his execution(…) method is invoked because i can see the output in the console, but after that an exception is raise and the Alfresco Workflow Console shows the message: org.alfresco.service.cmr.workflow.WorkflowException: 05110007 Workflow path activiti$3205 does not exist.
It seems that the problem is between the serviceTask and the endEvent transition…

The message is not logged in alfresco.log file, is there another configuration in addition to log4j.logger.org.alfresco.repo.workflow=debug in order to log also that message?

Francesco

kavilash23
Champ on-the-rise
Champ on-the-rise
Hi Francesco,

Try adding this line in log4j.properties

log4j.logger.workflow.sample.serviceTask.HelloWorldServiceTask=debug

checco
Champ in-the-making
Champ in-the-making
Thanks,
I have just resolved the problem by adding only a userTask after the serviceTask and everything works fine!

Now i facing the problem of the delegate expression: i have tried either the bean id and the base name of the executor class but it dosen't works.

I finally adopted the jeff's solution, using the activiti:class attribute and the getServiceRegistry method.

wgcox
Champ in-the-making
Champ in-the-making
We ran into the issue of trying to call 'delegate' from an Activiti workflow in Alfresco 4.0.1 (haven't tried this in 4.0.2 yet).  I looked at the 'invitation-nominated' workflow as an example, as it makes use of delegates. However, our delegate was not accessible from the workflow. We worked through a couple of issues and got it to work, and hopefully this is helpful to folks:

1) Your bean must be registered in the activitiBeanRegistry.  This is a Map that uses the class name (as a String) as the key, with the class object as the value in the Map. The important thing here is that your bean id name should exactly match your class name (e.g. - case sensitive) so that it matches in the Map.

2) If your class extends the BaseJavaDelegate class, your class should get added to the activitiBeanRegistry. However, this was not working for us. I attached a debugger, and I never saw my class getting added to the map.  We resolved this by making our custom class' bean dependent on the activitiBeanRegistry. So, it looks like there is an order of initialization issue here if you don't do this.

We have  bunch of classes that we're calling, so we just used an abstract bean that was dependent on the 'activitiBeanRegistry', and then our classes had the abstract bean as a parent (your Java class still extends BaseJavaDelegate, though).

Here is a snippet of the Spring config:

<bean id="AbstractWorkflowDelegate" parent="baseJavaDelegate" abstract="true" depends-on="activitiBeanRegistry"/>
   
   
    <bean id="MyCustomClass" parent="AbstractWorkflowDelegate" class="com.bluefishgroup.alf.workflow.MyCustomClass"/>
    
    <!– A bunch of additional classes defined as well –>

And then, in the source code, my class needs to still extend BaseJavaDelegate:


import org.alfresco.repo.workflow.activiti.BaseJavaDelegate;

public class MyCustomClass extends BaseJavaDelegate

ungawunga
Champ in-the-making
Champ in-the-making
Thanks for posting that, but it hasn't solved my problem. All the combinations I've found in the forums and tried has not gotten me a reference to the ServiceRegistry. I am implementing an ExecutionListener, and my object does get called from the workflow, so I know that part is correct. But when my object's 'notify' method is called, it never gets a non-null return from BaseJavaDelegate.getServiceRegistry().

What is the magic Spring incantation I'm missing here?


<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>
   <bean id="AbstractWorkflowDelegate" parent="baseJavaDelegate" abstract="true" depends-on="activitiBeanRegistry" />

   <bean id="MyIssuePost" class="com.epnet.alfresco.metadata.listener.MyIssuePost" parent="AbstractWorkflowDelegate">
      <property name="serviceRegistry" ref="ServiceRegistry" />
   </bean>

<!–  this didn't work either    
    <bean id="com.epnet.metadata.listener.MyIssuePost" class="com.epnet.alfresco.metadata.listener.MyIssuePost">
      <property name="serviceRegistry" ref="ServiceRegistry" />
   </bean>
–>
</beans>


scundall
Champ in-the-making
Champ in-the-making
I am facing same problem as UngaWUnga do

My code is…

public abstract class DmsCommonListener {

   final static protected String DMS_LOG_MARKER = "### DMS ###";

   @Autowired
   @Qualifier("ServiceRegistry")
   private ServiceRegistry serviceRegistry;
   
   /**
    * @param serviceRegistry
    *            the serviceRegistry to set
    */
   @Required  //I combined it to just somehow make it work:-)
   public void setServiceRegistry(ServiceRegistry serviceRegistry) {
      this.serviceRegistry = serviceRegistry;
   }

   /**
    * @return the serviceRegistry
    */
   public ServiceRegistry getServiceRegistry() {
      return serviceRegistry;
   }

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config />
   <context:component-scan base-package="com.tieto" />

   <bean id="DmsCustomMailer" class="com.tieto.workflow.util.DmsCustomMailer"></bean>
   <bean id="DmsCommonListenerBean" class="com.tieto.workflow.DmsCommonListener" abstract="true">
      <property name="workflowService">
         <ref bean="WorkflowService" />
      </property>
      <property name="serviceRegistry">
         <ref bean="ServiceRegistry" />
      </property>
   </bean>

<bean id="DmsCommonTaskListenerBean" class="com.tieto.workflow.DmsCommonTaskListener" abstract="true" parent="DmsCommonListenerBean" />
   <bean id="DmsCommonExecutionListenerBean" class="com.tieto.workflow.DmsCommonExecutionListener" abstract="true" parent="DmsCommonListenerBean" />

   <!– INIT –>
   <bean id="InitTaskListenerBean" class="com.tieto.workflow.init.TaskListener" parent="DmsCommonTaskListenerBean" />
   <bean id="InitExecutionListenerBean" class="com.tieto.workflow.init.ExecutionListener" parent="DmsCommonExecutionListenerBean" />
   <!– ELABORATION –>
   <bean id="ElaborationTaskListenerBean" class="com.tieto.workflow.elaboration.TaskListener" parent="DmsCommonTaskListenerBean" />

cafebabe
Champ in-the-making
Champ in-the-making
By registering the bean with activeRegistry, I was able to invoke it using the "delegateExpression" attribute as shown above.
But if I try to auto-wire a custom service class inside ExternalReviewNotification, then that class is not getting instantiated.
<blockcode>
<util:map id="activitiBeanRegistry" map-class="java.util.HashMap">
    <entry key="services" value-ref="ServiceRegistry" />
    <entry key="externalReviewNotification" value-ref="externalReviewNotification" />
    </util:map>
   
<bean id="externalReviewNotification" class="com.someco.bpm.ExternalReviewNotification"
depends-on="activitiBeanRegistry">
   <property name="myActionService">
      <ref bean="myActionService" />
   </property>
</bean>
<bean id="myActionService" class="com.someco.bpm.service.MyActionService"/>
</blockcode>
Please advise.

rasm
Champ in-the-making
Champ in-the-making
Getting started

Tags


Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.