cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with JBPMSpringActionHandler

bcoulson
Champ in-the-making
Champ in-the-making
All

I am attempting to connect to my Java class from within an advanced worfklow step. I have defined my process definition as follows.


<?xml version="1.0" encoding="UTF-8"?>

<process-definition  xmlns="urn:jbpm.org:jpdl-3.1"  name="scwf:publishDocument">

<swimlane name="initiator"/>

   <start-state name="Start">
      <task name="scwf:assignWorkflow" swimlane="initiator"/>
      <transition to="AnalystTask" name="toAnalyst"></transition>
   </start-state>

   <task-node name="AnalystTask">
      <task name="scwf:createDocument" swimlane="initiator">
         <event type="task-create">
            <script>
               if (bpm_workflowDueDate != void) taskInstance.dueDate = bpm_workflowDueDate;
                  if (bpm_workflowPriority != void) taskInstance.priority = bpm_workflowPriority;
            </script>
         </event>
      </task>
      <transition to="TeamLeadTask" name="toTeamLead">
           <action class="gov.dhs.ipds.alfresco.AlfrescoHelper" config-type="bean" name="reviewChanges"/>
      </transition>
   </task-node>

   <task-node name="TeamLeadTask">
      <task name="scwf:reviewDocument" swimlane="initiator">
         <event type="task-create">
            <script>
               if (bpm_workflowDueDate != void) taskInstance.dueDate = bpm_workflowDueDate;
                  if (bpm_workflowPriority != void) taskInstance.priority = bpm_workflowPriority;
            </script>
         </event>
      </task>

      <transition to="End" name="toProduction">
      </transition>
   </task-node>

   <end-state name="End"></end-state>
</process-definition>

And my Java code is as follows

package gov.dhs.ipds.alfresco;

import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler;
import org.springframework.beans.factory.BeanFactory;
import org.jbpm.graph.exe.ExecutionContext;

public class AlfrescoHelper extends  JBPMSpringActionHandler {

   private static final long serialVersionUID = 1000L;

   public void execute(ExecutionContext ctx) throws Exception {
      System.out.println("Inside AlfrescoHelp.execute()");
   }

   public AlfrescoHelper() {
      System.out.println("Inside AlfrescoHelper()");
   }
   
   @Override
   protected void initialiseHandler(BeanFactory factory) {
      System.out.println("Inside AlfrescoHelper.initialiseHandler()");
      // TODO Auto-generated method stub
   }
}

When I attempt to execute the workflow task that instantiates the Java action class, I get the following exception(s) in my logfile.


09:06:44,209  ERROR [web.context.ContextLoader] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gov.dhs.ipds.alfresco.AlfrescoHelper' defined in file [C:\Alfresco\tomcat\shared\classes\alfresco\extension\someco-model-context.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [gov.dhs.ipds.alfresco.AlfrescoHelper]: Constructor threw exception; nested exception is java.lang.NullPointerException
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:946)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:890)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
   at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
   at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:287)
   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
   at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:557)
   at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:842)
   at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:416)
   at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:261)
   at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:192)
   at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
   at org.alfresco.web.app.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:63)
   at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3972)
   at org.apache.catalina.core.StandardContext.start(StandardContext.java:4467)
   at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
   at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
   at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:546)
   at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:637)
   at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:563)
   at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:498)
   at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1277)
   at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:321)
   at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
   at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
   at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
   at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
   at org.apache.catalina.core.StandardService.start(StandardService.java:519)
   at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
   at org.apache.catalina.startup.Catalina.start(Catalina.java:581)
   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.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
   at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [gov.dhs.ipds.alfresco.AlfrescoHelper]: Constructor threw exception; nested exception is java.lang.NullPointerException
   at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141)
   at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:72)
   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:938)
   … 38 more
Caused by: java.lang.NullPointerException
   at org.springmodules.workflow.jbpm31.JbpmFactoryLocator.useBeanFactory(JbpmFactoryLocator.java:162)
   at org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler.<init>(JBPMSpringActionHandler.java:46)
   at gov.dhs.ipds.alfresco.AlfrescoHelper.<init>(AlfrescoHelper.java:15)
   at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
   at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
   at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
   at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
   at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126)
   … 40 more

I cannot see what I am doing wrong nor have I been able to find any information in the forums here or on Spring or jBpm to determine what I am doing wrong. I have not added a Spring bean for my Java class. When I do add a bean for it, I get the same exception above so I just get it sooner rather than later - basically at instantiation time.

Any help would be greatly appreciated.
39 REPLIES 39

bcoulson
Champ in-the-making
Champ in-the-making
All

I have been looking into this problem further and have more details and really hope someone out there can help me solve this one. So I am pretty certain the issue is with the BeanFactory. The line of code that is causing the problem in JBPMSpringActionHandler is the line that calls factoryLocator.useBeanFactory(null) in the code fragment below.


    protected JBPMSpringActionHandler()
    {
        // The following implementation is derived from Spring Modules v0.4
        BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
        BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
        initialiseHandler(factory.getFactory());
    }

I then looked into the JbpmFactoryLocator class (a Spring class). I can only find version 0.5 online of the source so I am *assuming* that the difference between 0.4 and 0.5 for this file is negligible as I am looking at line 162 for the problem.


   public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
144      // see if there is a default FactoryBean
145      BeanFactory factory;
146
147      if (factoryKey == null) {
148         if (!canUseDefaultBeanFactory)
149            throw new IllegalArgumentException(
150                  "a non-null factoryKey needs to be specified as there are more then one factoryKeys available ");
151         factory = defaultFactory;
152      }
153      else {
154         factory = (BeanFactory) beanFactories.get(factoryKey);
155         if (factory == null)
156            throw new IllegalArgumentException("there is no beanFactory under key " + factoryKey);
157      }
158
159      // increment counter
160      synchronized (referenceCounter) {
161         Integer counter = (Integer) referenceCounter.get(factory);
162         referenceCounter.put(factory, new Integer(counter.intValue() + 1));
163      }
164

Line 162 makes reference to the factory variable and I believe that may be null. Here is why. In the above code, it is possible for defaultFactory to be null IF canUseDefaultBeanFactory == true AND defaultFactory is null (which is the case if setBeanFactory is not called on the BeanFactory. Code for setBeanFactory below).


   public void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
57
58       // add the factory as default if possible (if it's the only one)
59       synchronized (JbpmFactoryLocator.class) {
60          if (canUseDefaultBeanFactory) {
61             if (defaultFactory == null) {
62                defaultFactory = beanFactory;
63                if (logger.isDebugEnabled())
64                   logger.debug("default beanFactoryReference=" + defaultFactory);
65             }
66             else {
67                if (logger.isDebugEnabled())
68                   logger.debug("more then one beanFactory - default not possible to determine");
69                canUseDefaultBeanFactory = false;
70                defaultFactory = null;
71             }
72          }
73       }
74
75       // add name
76       addToMap(factoryName, beanFactory);
77       Integer counter = (Integer) referenceCounter.get(beanFactory);
78
79       if (counter == null)
80          referenceCounter.put(beanFactory, new Integer(0));
81
82       // add aliases
83       String[] aliases = beanFactory.getAliases(factoryName);
84       List names = new ArrayList(1 + aliases.length);
85       names.add(factoryName);
86       
87       for (int i = 0; i < aliases.length; i++) {
88          addToMap(aliases[i], beanFactory);
89          names.add(aliases[i]);
90       }
91
92       // append previous found names
93       List previousNames = (List)beanFactoriesNames.get(beanFactory);
94       if (previousNames != null)
95          names.addAll(previousNames);
96       
97       beanFactoriesNames.put(beanFactory, names);
98       
99    }
100

Furthermore I noticed the AlfrescoJbpmConfigurationFactoryBean class that implements BeanFactoryAware and FactoryBean<JbpmConfiguration> and i can see where it is included in the Spring context file (workflow-context.xml) as shown below.


   <bean id="jbpm_configuration" class="org.alfresco.repo.workflow.jbpm.AlfrescoJbpmConfigurationFactoryBean">
      <property name="sessionFactory" ref="sessionFactory"/>
      <property name="configuration" value="classpath:org/alfresco/repo/workflow/jbpm/jbpm.cfg.xml"/>
   </bean>

Several questions.

1. What i cannot figure out is who calls setBeanFactory - is that done internally by Spring?
2. Do I need to register my Java class as a Spring bean? All other posts I have seen in this forum regarding a Java action for an advanced worfklow step do not mention the need to do this.But it seems as if there is an issue with my Spring configuration so I would like to know if this is a requirement that I am missing. If I do need to specify it, what, if anything, do I specify as parent attribute for bean?
3. Do I need to do anything else other than defining a Java class that extends JbpmSpringActionHandler and making a reference to it from my processdefinition file, and adding dependency jars to Alfresco?
4. Are there special jar files I need in addition to what is already in Alfresco?
5. Is the AlfrescoJavaScript class registered as a Spring bean? I thought if I could see its bean configuration, it may help me understand how to, if necessary, configure the Spring bean for a different ActionHandler.

Any help is greatly appreciate. I have been struggling with this for quite some time.

bcoulson
Champ in-the-making
Champ in-the-making
One more question - does it matter if I run this in Explorer or Share? I had assumed not, but wanted to point out that I am attempting to build this workflow in Share so that is where this behavior is exhibited. In fact, I can't even get my workflow to run in Explorer due to a TransientNode: taskId property not found error.

mcook
Champ in-the-making
Champ in-the-making
I have recently just created my own ActionHandler in Java and had very little problems…

I noticed in your processdefinition.xml file, your action tag had the following attribute:

config-type="bean"

I have not actually specified this as my action is not a bean.  Take a look at some snippets from my configs:

processdefinition.xml:
      <task-node name="set-document-type">
         <task name="blfinwf:setDocumentTypeTask" swimlane="initiator">
            <description>Set Document Type</description>
            
            <event type="task-end">
               <action class="com.burris.common.bpm.actions.ForceChangeTypeAction" />
            </event>
            
            <controller>
               <variable name="blfinwf_documentType" />
            </controller>
         </task>
         
         <transition name="Submit" to="set-meta-data"></transition>
      </task-node>

new-document-workflow-model.xml:
      <type name="blfinwf:setDocumentTypeTask">
         <parent>bpm:workflowTask</parent>
         
         <properties>
            <property name="blfinwf:documentType">
               <type>d:text</type>
               <mandatory>true</mandatory>
               <multiple>false</multiple>
               
               <constraints>
                  <constraint type="LIST">
                     <parameter name="allowedValues">
                        <list>
                           <value>blfin:certificateOfLiabilityInsurance</value>
                           <value>blfin:1099</value>
                           <value>blfin:w9</value>
                        </list>
                     </parameter>
                  </constraint>
               </constraints>
            </property>
         </properties>
      </type>

ForceChangeTypeAction.java
package com.burris.common.bpm.actions;

import java.util.List;

import org.alfresco.repo.workflow.jbpm.JBPMNode;
import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.log4j.Logger;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.taskmgmt.exe.TaskInstance;
import org.springframework.beans.factory.BeanFactory;

@SuppressWarnings("serial")
public class ForceChangeTypeAction extends JBPMSpringActionHandler {

   private static final Logger log = Logger.getLogger( ForceChangeTypeAction.class );
   
   private NodeService nodeService;
   private NamespaceService namespaceService;
   
   @Override
   protected void initialiseHandler( BeanFactory factory ) {
      
      this.nodeService = (NodeService) factory.getBean( "nodeService" );
      this.namespaceService = (NamespaceService) factory.getBean( "namespaceService" );
   }
   
   @Override
   public void execute( ExecutionContext context ) throws Exception {
      
      ContextInstance contextInstance = context.getContextInstance();
      
      Object object = contextInstance.getVariable( "bpm_package" );
      if ( object == null ) {
         
         log.fatal( "bpm_package variable is null." );
         return;
      }
      
      NodeRef nodeRef = ((JBPMNode) object).getNodeRef();
      if ( nodeRef == null ) {
         
         log.fatal( "nodeRef is null." );
         return;
      }
      
      TaskInstance task = context.getTaskInstance();
      String documentType = (String) task.getVariable( "blfinwf_documentType" );
      
      QName qname = QName.createQName( documentType, namespaceService );
      
      // Set document to finance doc type to ensure child type compatibility
      // (ie someone dropped a document with a type already specified)
      List<ChildAssociationRef> children = nodeService.getChildAssocs( nodeRef );
      for ( ChildAssociationRef child : children ) {
         
         NodeRef childNodeRef = child.getChildRef();
         nodeService.setType( childNodeRef, qname );
      }
   }
}

Let me know if this helps.

bcoulson
Champ in-the-making
Champ in-the-making
Thanks - this does help to know that I am not going crazy. I did actually already remove the config-type attribute but it made no difference unfortunately. Question - did you have to add a bean to your spring configuration files? if so, could you please provide me that configuration detail? What version of Alfresco are you using BTW?

Thanks!
Brenda

mcook
Champ in-the-making
Champ in-the-making
I did not have to create a bean in the spring configuration files and we are running Alfresco Enterprise v3.4.0.

mcook
Champ in-the-making
Champ in-the-making
Based on the error, it looks like there is a problem in your someco-model-context.xml file.  Could you post it in its entirety so I can take a look at it?

bcoulson
Champ in-the-making
Champ in-the-making
Sure. Here is my context file.


<?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="extension.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
      <property name="models">
         <list>
            <value>alfresco/extension/model/scWorkflowModel.xml</value>
         </list>
      </property>
   </bean>
   <bean id="extension.workflowBootstrap" parent="workflowDeployer">
      <property name="labels">
         <list>
            <value>alfresco/extension/scWorkflow</value>
         </list>
      </property>
   </bean>   
</beans>

Thank you very much!!

mcook
Champ in-the-making
Champ in-the-making
Ok so I dont think the problem is with your someco config file.  Reading further down in the log file, I see this:

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [gov.dhs.ipds.alfresco.AlfrescoHelper]: Constructor threw exception; nested exception is java.lang.NullPointerException

In the class I have defined, I did not specify a default constructor.  I don't see why having this there is an issue, but I'd say comment it out or remove it and give that a try.

bcoulson
Champ in-the-making
Champ in-the-making
thanks for the quick reply. I should have said earlier - I noticed that myself and removed my default constructor. As you say, it is a difference between your solution and mine. However, my problem prevails - it made no difference to the behavior.

here is my new java code


package gov.dhs.ipds.alfresco;

import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler;
import org.springframework.beans.factory.BeanFactory;
import org.jbpm.graph.exe.ExecutionContext;

public class AlfrescoHelper extends  JBPMSpringActionHandler {

   private static final long serialVersionUID = 1000L;

   public void execute(ExecutionContext ctx) throws Exception {
      System.out.println("Inside AlfrescoHelp.execute()");
   }
   
   @Override
   protected void initialiseHandler(BeanFactory factory) {
      System.out.println("Inside AlfrescoHelper.initialiseHandler()");
      // TODO Auto-generated method stub
   }
}

I am quite certain that I have a null BeanFactory based on the line of code where it is breaking but the question is why is my beanFactory null?