8 Replies Latest reply on Aug 22, 2010 5:04 AM by cbensemann

    Jbpm rant

    cbensemann

      Ok. I  have been trying to use Jbpm and Seam for my current project. The following is a rant about jbpm. I had to let my frustrations out so here goes. The following are my personal opinions and experiences. You have been warned :)



      I have been using jbpm with varying levels of success in my current project for about 9 months. Getting it to work in seam isn't as easy as people make out. Sure it works if you just want a basic implementation but as soon as you try to use reminders or any scheduled feature you basically have to start extending the seam jbpm component because you cant enable the scheduler in the default implementation! I only found that out by posting on the jbpm forum and getting some quite rude responses from a particular individual that is very knowledgeable about jbpm but spends his time telling users of the forum to google the answer or read the source/unit tests (which by the way aren't very well javadoc'd). Having worked that out the actual implementation is not that hard and is documented on this site somewhere but you still need to know you need to do it. The same post also talks about versioning of your definitions to stop them from being continually re-defined every jboss server restart.


      Ok so jbpm is now up and running and sending reminders. Now to the next problem - I have just realised that the ForEachForkActionHandler part of my jbpm process isn't doing what its meant to. I need it to spawn tasks and assign those to users. To do this an object is persisted in jbpm (locally to the task-node) and then should be read out and used when the task is initialised. Not the case it seems (see my other post called jbpm woes and help me if you can).


      To try and solve this problem I tried upgrading to the latest version - a task which should be as simple as getting the latest version from the jbpm website. So I head over there and get version 3.2.7 (version 4.x is not supported in seam) I deploy and immediately get an issue. A quick google shows I need to add <mapping resource="org/jbpm/db/hibernate.types.hbm.xml" /> to my hibernate.cfg.xml. Yay it deployed! First attempt to use it finds another bug. Looking in jira its fixed in version 3.2.9 - What?!?! I just got the latest version from their website! - it seems not. Looking in jira shows there are versions 3.2.8, 3.2.9, 3.2.10. then I notice 3.3.0 and 3.3.1 (surely 3.3.1 is newer than 3.2.x so I get that). Wrong again it apears to be older. 3.2.9 is the latest. But that is no where to be found online and 3.2.8 still has the bug in it :(


      So whats the deal? Jbpm documentation is large and often of limited help. The forums are less than helpful as you usually just get a look in the code type response. and you cant even be sure what the latest version of the code is!


      Now I might have overlooked something obvious. Perhaps all the problems I've had are easily fixable and there is a clear link to the latest code somewhere in which case I will bite my tongue and appologise but I have used many many open source libraries over the years and have never encountered one which is proving quite so difficult to use.



      Craig

        • 1. Re: Jbpm rant
          tony.herstell1

          Experiences like this steer people away from jBPM which is a shame as it's one of the strong reasons to use Seam!


          The Doco for Seam and RF is generally excellent (tutorial-doco) as far as it goes; perhaps someone can look into the chapters on jBPM?

          • 2. Re: Jbpm rant
            tsurdilovic

            Cross-referencing to your jbpm woes post as you are doing it here too :)
            Think you don't have full understanding of what the ForEachForkActionHandler does (from other out post you write My understanding of the ForEachForkActionHandler is that the variables in list will be iterated over and for each one a new task is created and the then a locally scoped variable created to store the item.).


            This is wrong, as the ForEachForkActionHandler only creates tokens to branch the current execution (just like a Fork, but the number of legs are dynamic). The task creation is happening in the task node following the ForEachActionHandler, and the task assignment is modeled there as:


               


            <task-node name="complete_corrective_action" >
                   <task notify="true" duedate="1 business week" description="#{action.summary}" >
                        <assignment actor-id="#{action.owner.email}" />
                    </task>
                    <transition to="corrective_actions_join" />
                </task-node>





            Also from your other post , not sure what


            #{action.owner.email}



            should resolve to, or why you expects it to resolve to a different value for each created task, as all tasks are created in the same context.


            And just to mention, you know that Red Hat offers support for Seam and jBPM which may be helpful ;)

            • 3. Re: Jbpm rant
              cbensemann

              Well I think the other post is a more appropriate place to discuss the ForEachForkActionHandler but I will reply here.


              The ForEachForkActionHandler does create variables


              newExecutionContext.getContextInstance().createVariable(as, item, newToken);
              



              This variable is created in the scope of the token as per the following documentation from the ContextInstance class


              /*
               * creates a variable in the scope of the given token and calculates the actual VariableInstance-type from the value.
               */
              public void createVariable(String name, Object value, Token token)



              From this I would expect that variable (which is unique to each token) to be available when the task instance is created thus #{action.owner.email} should resolve to a different value for each token as the ForEachForkActionHandler has created a variable action and saved an object under that variable name.


              The problem I believe is that Seam only ever expects there to be one task instance per conversation but when using the ForEachForkActionHandler multiple are created within the same conversation and the variable is not correctly resolved.


              To me this all seems pretty clear as to how it should work. If this is not the case then please explain what its actually doing and why a variable per token is created if it then can not be used?


              • 4. Re: Jbpm rant
                tony.herstell1

                Hi Tihomir,


                Thank you for you answer in support of the problem we are experiencing.


                The support we get for Seam stack is usually excellent and keeps us using the technology.


                We (Craig) actively supports the forums (at the companies cost).


                Craig is quite clever and in fact still has the most simple and elegant solution for adding fields dynamically to forms in Seam that I have seen (Something we may be willing to show at a seam forum someday).


                Anyhow, back to support:


                RF guys have even synced to a project to spot a particularly gnarly problem a couple of times (one was when extending the basic RF tree component (the ideas behind, with any luck, might appear in RF 4 onwards)). They even asked us if they can showcase the current project (SaaS) when launched.


                MyEclipse guys have fixed bugs we have raised and have, also, on two occasions synced with a project to find some exploded deployment issues (which were bugs in MyEclipse and being fixed will benefit the whole MyEclipse use base.. One was validation errors and the other was having rouge files in our referenced libraries which a Mac machine had left behind that was causing issues when exploded deployment was in effect).


                Due to the high quality of the Seam doco; we have not needed to sync up with any seam developers that I know of so far. Albeit we have used the forums.


                As we provide training for the Seam stack (only for preferred customers) we are keen to dive into Seam more than usual users and try to resolve problems ourselves and I am sure you understand why we do this. We generally leave these corporates clients with the recommendation that they sign up to Red Hat for longer term support.


                We are more focused on to market products that fly the flag for the Seam stack.


                To this end we have just released the product as an Alpha to a friend customer with the above problem (JBPM) so are keen to solve it before we go for full launch in January.


                We are not adverse to paying for support but as yet we don't seem to be on the same page as to the nature of the problem.


                :)

                • 5. Re: Jbpm rant
                  lvdberg

                  Hi,


                  First, let's try to get an answer to your problem in one of the two threads you created, so please stop one of them ;-)


                  I was triggered by Craig's remark about the Seam converaation:



                  The problem I believe is that Seam only ever expects there to be one task instance per conversation but when using the ForEachForkActionHandler multiple are created within the same conversation and the variable is not correctly resolved.


                  I personally think this is the way it should be. The default Seam conversation fully spans a single Use Case and NOT a Business Process. A Business process can contains multiple tasks for multiple users. The Seam support for Task-related stuff is great, but whenever you want something different, you have to add it yourself (that's what I did)  So IMHO you implement one Use Case to get the additional Tasks and another to use them.


                  Leo


                  P.S. I am using the term default conversation here, because Seam also uses conversations on the BP-level, which you should enter without having a conversation active (there is no join eq true on the CreateTask or beginTask annotations.

                  • 6. Re: Jbpm rant
                    cbensemann

                    Thanks Leo,


                    Constructive comments as always :)


                    I also agree that it makes sense that you have one conversation for the piece of work associated with one task and then another to use those new tasks. That is effectively what I am trying to do.


                    Inside a conversation I create a number of tasks for people to do. These tasks incorrectly get assigned the wrong data. It appears that each task created is randomly picking up whatever is in the current conversation scope rather than each value that is supplied using a for each loop inside the ForEachForkActionHandler.


                    The problem comes in this case because those tasks are created inside the existing conversation. Should those tasks have been created correctly another user would log in and begin a new conversation to work on those tasks.


                    I've spent most of the day working on other things but should be free to look into this again tomorrow. It's entirely possible I'm going about this the wrong way? My objective is to let one person create an arbitrary number of tasks and assign them to other people to do. Those people then do the tasks and the bpm flow then joins allowing the original user to review what the others have done and then continue down the business process.


                    Craig

                    • 7. Re: Jbpm rant
                      lvdberg

                      Hi Craig,


                      My suggestions:


                      - Start the conversation
                      - Create an instance of an HelperClass, This class contains the userdata you want to pass to jBPM,
                      - Put these instances in a Map (myMap) and let the key be the username (assuming there one single user just gets one task, otherwise use another unique key) or just use the list amd
                      - generate whatever async event(this.is.my.bpm.event, myMap);
                      - Close your use Case !!


                      Inside the Async method
                      - Process the Map/List inside an observing method using jbpmContext (make this method Transactional)
                      - After procesing, generates another event(this.is.my.new.task.event)
                      - Update whatever you need to update


                      This approach separates basically the taskcreation from the rest, because you finish your own convesration and by using the event you span a new Seam-managed thread which processes your additional task-request. In this scenario you're NOT using seam-managed variable (because that semas to go wrong) but you manage your own data.


                      This is more or less the way I integrate Seam and jBPM by using async communication (although I don't dynamically create addtional tasks)  .


                      Hopefully useful,


                      Leo

                      • 8. Re: Jbpm rant
                        cbensemann

                        Thanks for the suggestions Leo. I came up with the following solution while looking into using asynchronous events. The solution doesn't actually use events though :)


                        So I use the ForEachForkActionHandler to fork my process up as I did before. This creates a number of new tokens which are then transitioned to the next node where task instances are created for them. I then attach an action handler to the task-create event and manually grab the token scoped variable and use it to set the actorId and description.


                        Iin the process definition I have the following


                            <node name="corrective_actions">
                               <action
                                    class="nz.co.softwarefactory.esafensound.util.ForEachForkActionHandler"
                                    config-type="bean">
                                    <listVariable>correctiveActions</listVariable>
                                    <as>action</as>
                                </action>
                                <transition to="complete_corrective_action" />
                            </node>
                        
                            <task-node name="complete_corrective_action" >
                               <task notify="true" duedate="1 business week">
                                    <event type="task-create">
                                        <action class="nz.co.softwarefactory.esafensound.util.ForkTaskAssignmentHandler" config-type="bean" />
                                    </event>
                                </task>
                                <transition to="corrective_actions_join" />
                            </task-node>
                        
                        



                        The ForkTaskAssignmentHandler looks like:


                        public class ForkTaskAssignmentHandler implements ActionHandler {
                        
                            /**
                             * @param executionContext
                             * @return
                             */
                            private CorrectiveAction lookupCorrectiveAction(final ExecutionContext executionContext) {
                                return (CorrectiveAction) executionContext.getVariable("action");
                            }
                        
                            /*
                             * (non-Javadoc)
                             *
                             * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
                             */
                            @Override
                            public void execute(final ExecutionContext executionContext) throws Exception {
                                final TaskInstance taskInstance = executionContext.getTaskInstance();
                                final CorrectiveAction correctiveAction = lookupCorrectiveAction(executionContext);
                                taskInstance.setActorId(correctiveAction.getOwner().getEmail());
                                taskInstance.setDescription(correctiveAction.getSummary());
                                taskInstance.setDueDate(correctiveAction.getDueDate());
                            }
                        }
                        



                        I'm not sure this is the best solution but it is a working solution.