1 2 3 4 Previous Next 54 Replies Latest reply on Oct 28, 2006 8:06 PM by aguizar Go to original post
      • 30. Re: MessageService and JMS
        mteira

        Hello again.

        In my quest for the "working jBPM-JMS environment" I've found a new problems, and I'm wondering if this is the right forum to inform about them. I posted one of them in the Users Forum, but then, I thought that perhaps this is a better place since CVS version and new features are involved.

        So, what is the preferable way to proceed. Post them here? Open JIRA bugs directly?

        While I wait for your answer, here is the link to one of the problems I've found:
        http://www.jboss.com/index.html?module=bb&op=viewtopic&t=92188

        I'm thinking that perhaps a workaround could be to comment out the 'web' descriptor in the application.xml ear file, and deploy into my jboss both the console war and the jbpm.ear.

        Is there any code in the repository to test the JMS service messaging from the client side? I mean, something able to create the Command objects, and send them to the proper JMS queue. Looking at the code it seems to me that what I need is to create those Command subclass object (for example, a NewProcessInstanceCommand) and just send it to the queue where the CommandListener MDB is attached. Anyway, as the Command subclasses don't have a constructor, and a lot of getter and setter methods, I'm not sure of what setter methods should be invoked to create a valid Command object, but I suppose that it depends on the subclass I'm using.

        Any comment about this "memory dump" ?

        Regards.

        • 31. Re: MessageService and JMS
          tom.baeyens

           

          "mteira" wrote:
          So, what is the preferable way to proceed. Post them here? Open JIRA bugs directly?


          please post your problems here in this forum first. since you are working on HEAD of CVS and you don't ask beginners questions, this is the best place.

          • 32. Re: MessageService and JMS
            tom.baeyens

             

            "mteira" wrote:
            While I wait for your answer, here is the link to one of the problems I've found:
            http://www.jboss.com/index.html?module=bb&op=viewtopic&t=92188


            That will probably have to do with the classloading. By default, .war's are loaded in a separate classloading environment that can see the libraries in the server's lib folder and the classes and libs defined in the .war's itself.

            .ears have a different classloading mechanism. By default, the .ear's are loaded in the global classpath. (Meaning that they share the same classloader repository as the global classloader).

            So classes in .ear files will be visible to the global classpath and classes in .war files are not (by default).

            I'm not yet sure, but i can only expect that this problem somehow must boil down to that.

            "mteira" wrote:
            I'm thinking that perhaps a workaround could be to comment out the 'web' descriptor in the application.xml ear file, and deploy into my jboss both the console war and the jbpm.ear.



            if that works for you, it could be a temporary workaround.

            "mteira" wrote:

            Is there any code in the repository to test the JMS service messaging from the client side?


            indeed. i was busy trying to create the .ear packaging when i got interrupted in this line of work. so here's the todo in the sequence that i had in mind:

            1) create a decent .ear packaging with jbpm and the mdb and the slsb. the packaging should also contain the configuration that binds the jbpm messaging service to JMS.

            2) create a test set up so that messaging can be tested. i got started on this by incorporating cactus. i have one cactus test somewhere that is able to print a log message inside of jboss.

            3) create test cases that execute processes with async="true" and run these inside of the container and check if the JMS queues contain the proper jobs.

            "mteira" wrote:

            Looking at the code it seems to me that what I need is to create those Command subclass object (for example, a NewProcessInstanceCommand) and just send it to the queue where the CommandListener MDB is attached.


            yes.

            "mteira" wrote:

            Anyway, as the Command subclasses don't have a constructor, and a lot of getter and setter methods, I'm not sure of what setter methods should be invoked to create a valid Command object, but I suppose that it depends on the subclass I'm using.


            use the setters. the commands are a work in progress. note that the use cases for commands are still being discovered/examined. e.g. relation between web services and commands still needs to be worked out in detail. it could be that the commands will be subject to change.

            after the use cases for commands become clear and they have stabilized a bit, we can start creating convenience constructors.

            • 33. Re: MessageService and JMS
              mteira

              Hello.

              1.-I've found the problem with JSF and jbpm.ear. It was my fault (once again). It seems that the cause was that, perhaps for not running the clean target, the ear customizedwar lib directory was holding both a Sun JSF implementation and a MyFaces apache one. I suppose that the implementation was switched in some moment, and I didn't clean up my target directory as frequently as I should. BTW, deploying the jbpm-console.war and the jbpm.ear (with the 'web' node commented out) at the same time was not a valid workaround, as I run into problems with the ehcache (it looked like an NPE trying to create a second CacheManager).

              2.-Before trying to setup a working cactus environment, I just wanted to create an standalone JMS client and just send a message to the JbpmCommandQueue to see how it works.

              I run into some problems with the MDB CommandListener trying to locate the CommandService Session Bean. I patched as:

              ### Eclipse Workspace Patch 1.0
              #P jbpm
              Index: enterprise/cmdlistener/src/main/java/org/jbpm/ejb/impl/CommandListenerBean.java
              ===================================================================
              RCS file: /cvsroot/jbpm/jbpm.3/enterprise/cmdlistener/src/main/java/org/jbpm/ejb/impl/CommandListenerBean.java,v
              retrieving revision 1.1
              diff -u -r1.1 CommandListenerBean.java
              --- enterprise/cmdlistener/src/main/java/org/jbpm/ejb/impl/CommandListenerBean.java 24 Aug 2006 16:03:45 -0000 1.1
              +++ enterprise/cmdlistener/src/main/java/org/jbpm/ejb/impl/CommandListenerBean.java 10 Oct 2006 16:22:29 -0000
              @@ -70,8 +70,8 @@
               try {
               log.debug("looking up local command service");
               Context initial = new InitialContext();
              - Context environment = (Context) initial.lookup("java:comp/env/ejb");
              - LocalCommandServiceHome localCommandServiceHome = (LocalCommandServiceHome) environment.lookup("LocalCommandServiceHome");
              + Context environment = (Context) initial.lookup("java:comp/env");
              + LocalCommandServiceHome localCommandServiceHome = (LocalCommandServiceHome) environment.lookup("ejb/LocalCommandServiceBean");
               LocalCommandService localCommandService = localCommandServiceHome.create();
               try {
               // TODO add support for sending back the result
              
              


              I'm not running into some problems with hibernate that is not able to locate using JNDI the UserTransaction. I will investigate further, to see if it's caused by a missconfiguration.

              Regards.


              • 34. Re: MessageService and JMS
                mteira

                It seems that the problem is related with the fact that JBoss is not exposing the UserTransaction under java:comp/UserTransaction (that I think it's the standard or at least recommended place to expose it), it's exposed under the global JNDI namespace as 'UserTransaction'. So, I've made changes as shown in this patch:

                ### Eclipse Workspace Patch 1.0
                #P jbpm
                Index: jpdl/jar/src/main/config/hibernate.cfg.xml
                ===================================================================
                RCS file: /cvsroot/jbpm/jbpm.3/jpdl/jar/src/main/config/hibernate.cfg.xml,v
                retrieving revision 1.11
                diff -u -r1.11 hibernate.cfg.xml
                --- jpdl/jar/src/main/config/hibernate.cfg.xml 22 Sep 2006 14:23:25 -0000 1.11
                +++ jpdl/jar/src/main/config/hibernate.cfg.xml 11 Oct 2006 10:20:58 -0000
                @@ -26,7 +26,7 @@
                
                 <!-- JTA transaction properties (begin) ===
                 <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
                - <property name="jta.UserTransaction">java:comp/UserTransaction</property>
                + <property name="jta.UserTransaction">UserTransaction</property>
                 ==== JTA transaction properties (end) -->
                
                 <!-- CMT transaction properties (begin) ===



                Regards.


                • 35. Re: MessageService and JMS
                  mteira

                  After the previous changes, I was able to create new ProcessInstances for an already deployed ProcessDefinition called 'Async' using a JMS standalone client, basically doing:

                  NewProcessInstanceCommand npic = new NewProcessInstanceCommand();
                  npic.setProcessName("Async");
                  //Setup for JMS session and producer using JNDI (omitted)
                  ObjectMessage om = session.createObjectMessage();
                  om.setObject(npic);
                  producer.send(om);


                  The process instances are created, and I can see them into the Oracle database I'm using as datasource. But now, I'm a little confused about how to start those process instances:

                  My first attempt was to add to the 'start-state' node the attribute async with value 'true'. But it seems that's not valid under the DTD as I got that error while trying to deploy such process definition.

                  So, I guess that perhaps I should send a SignalCommand targetting that newly created process instance. To do so, it seems that I need to know the tokenId I want to signal (and it looks logical to me), but how could I know it from my JMS client.

                  What I'm going after is to be able to run the complete process inside the JBoss threads. I just want to launch it from the JMS client.

                  Why the start-state node can not be run asynchronously? Is that a design limitation?

                  Shouldn't I receive some feedback from my NewProcessInstanceCommand to know at least what ProcessInstance id I've launched (in order to send signals to that process instance tokens, for example) ?

                  What's the previousToken for, in the SignalCommand class ?

                  Regards.




                  • 36. Re: MessageService and JMS
                    tom.baeyens

                    take a look at the composite command. that gives you the option of wrapping multiple commands in one command. could be what you're looking for.

                    alternatively, we could consider adding a transitionName as part of the NewProcessInstanceCommand. if it is diff from null, then a signal is given with the given command. probably we would need to look at an elegant solution for the default transition...

                    • 37. Re: MessageService and JMS
                      mteira

                      Thanks for the tip Tom. That led me to understand what are the previous* fields in the Command subclasses supposed to be for.

                      Anyway, if I understand correctly, every command in the Composite list should accept the result of the previous command execution, providing a field with previous{Class name of the previous result command}.
                      So, to be able to compose a command with a NewProcessInstance and a signal to make it shake, I need SignalCommand to provide a previousProcessInstance field and be able to use it to get the root token of the newly created process instance to signal it.

                      Is that the way to proceed?

                      Regards.

                      • 38. Re: MessageService and JMS
                        mteira

                        I think I've found a bug in the CompositeCommand injection method. The problem is that findField method is only feeded with the class of the previous command result, and since it should search into the new Command class for a field suitable to be injected with the result of the previous command, I think it's wrong (at least it's not injecting). I've changed it and now seems to work:

                        ### Eclipse Workspace Patch 1.0
                        #P jbpm
                        Index: jpdl/jar/src/main/java/org/jbpm/command/CompositeCommand.java
                        ===================================================================
                        RCS file: /cvsroot/jbpm/jbpm.3/jpdl/jar/src/main/java/org/jbpm/command/CompositeCommand.java,v
                        retrieving revision 1.1
                        diff -u -r1.1 CompositeCommand.java
                        --- jpdl/jar/src/main/java/org/jbpm/command/CompositeCommand.java 23 Aug 2006 15:37:37 -0000 1.1
                        +++ jpdl/jar/src/main/java/org/jbpm/command/CompositeCommand.java 11 Oct 2006 15:15:59 -0000
                        @@ -5,6 +5,8 @@
                         import java.util.Iterator;
                         import java.util.List;
                        
                        +import org.apache.commons.logging.Log;
                        +import org.apache.commons.logging.LogFactory;
                         import org.jbpm.JbpmContext;
                         import org.jbpm.JbpmException;
                        
                        @@ -37,7 +39,7 @@
                         }
                        
                         protected void tryToInject(Object lastResult, Command command) {
                        - Field field = findField(lastResult.getClass());
                        + Field field = findField(lastResult.getClass(), command);
                         if (field!=null) {
                         field.setAccessible(true);
                         try {
                        @@ -48,10 +50,10 @@
                         }
                         }
                        
                        - protected Field findField(Class clazz) {
                        + protected Field findField(Class clazz, Command command) {
                         Field field = null;
                         int i=0;
                        - Field[] fields = clazz.getDeclaredFields();
                        + Field[] fields = command.getClass().getDeclaredFields();
                         while ( (i<fields.length)
                         && (field==null)
                         ) {
                        @@ -63,6 +65,9 @@
                         }
                         i++;
                         }
                        + log.debug("Field to inyect for class '"+clazz.getName()+"' is '"+field+"'");
                         return field;
                         }
                        +
                        + private static Log log = LogFactory.getLog(CompositeCommand.class);
                         }
                        


                        Also, I've added to the SignalCommand a new field as I commented before, to be able to send a composite command (NewProcessInstanceCommand,SignalCommand) with the latter using the ProcessInstance returned by the former:

                        ### Eclipse Workspace Patch 1.0
                        #P jbpm
                        Index: jpdl/jar/src/main/java/org/jbpm/command/SignalCommand.java
                        ===================================================================
                        RCS file: /cvsroot/jbpm/jbpm.3/jpdl/jar/src/main/java/org/jbpm/command/SignalCommand.java,v
                        retrieving revision 1.3
                        diff -u -r1.3 SignalCommand.java
                        --- jpdl/jar/src/main/java/org/jbpm/command/SignalCommand.java 23 Aug 2006 15:37:37 -0000 1.3
                        +++ jpdl/jar/src/main/java/org/jbpm/command/SignalCommand.java 11 Oct 2006 15:19:29 -0000
                        @@ -24,6 +24,7 @@
                         import org.apache.commons.logging.Log;
                         import org.apache.commons.logging.LogFactory;
                         import org.jbpm.JbpmContext;
                        +import org.jbpm.graph.exe.ProcessInstance;
                         import org.jbpm.graph.exe.Token;
                        
                         public class SignalCommand implements Command {
                        @@ -34,14 +35,23 @@
                         String transitionName = null;
                        
                         Token previousToken = null;
                        + ProcessInstance previousProcessInstance = null;
                        
                         public Object execute(JbpmContext jbpmContext) {
                         log.debug("executing "+this);
                        - Token token = getToken(jbpmContext);
                        - if (transitionName==null) {
                        - token.signal();
                        + if (previousProcessInstance!=null) {
                        + if (transitionName==null) {
                        + previousProcessInstance.signal();
                        + } else {
                        + previousProcessInstance.signal(transitionName);
                        + }
                         } else {
                        - token.signal(transitionName);
                        + Token token = getToken(jbpmContext);
                        + if (transitionName==null) {
                        + token.signal();
                        + } else {
                        + token.signal(transitionName);
                        + }
                         }
                         return null;
                         }
                        


                        It seems to work. But I've seen a log that says the MessageService used is the DB based one:


                        2006-10-11 17:01:55,472 DEBUG [org.jbpm.svc.Services] closing service 'message': org.jbpm.msg.db.DbMessageService@6be4cc
                        2006-10-11 17:01:55,483 DEBUG [org.jbpm.msg.db.DbMessageService] messages were produced the jobExecutor will be signalled
                        
                        


                        I suppose that (once again) is caused by a missconfiguration. How should I configure what message service implementation should be used?

                        Regards.


                        • 39. Re: MessageService and JMS
                          tom.baeyens

                          don't have time to comment in depth right now. but you are definitely on the right track.

                          • 40. Re: MessageService and JMS
                            mteira

                            Sorry for triggering questions that fast. I will try to control myself and investigate a little more before asking.

                            I've copied jbpm.cfg.xml to the jbpm/jpdl/jar/src/main/config/jbpm.cfg.xml and changed the message service to use the JMS based one:

                            <service name="message"
                             factory="org.jbpm.msg.jms.JmsMessageServiceFactoryImpl" />


                            Now, I'm getting NPE in JmsMessageServiceFactoryImpl openService. It happens at line 49:

                            ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup(connectionFactoryJndiName);


                            I see that the private member connectionFactoryJndiName is initialized to 'null' and there's no method to change it to another value. Is it injected from another place? Is there some code missing here?


                            Regards.



                            • 41. Re: MessageService and JMS
                              tom.baeyens

                               

                              "mteira" wrote:
                              Sorry for triggering questions that fast. I will try to control myself and investigate a little more before asking.


                              please keep it up. your contributions are good. let me know if you want committer access. tom dot baeyens at jboss dot com

                              "mteira" wrote:
                              I've copied jbpm.cfg.xml to the jbpm/jpdl/jar/src/main/config/jbpm.cfg.xml and changed the message service to use the JMS based one:

                              <service name="message"
                               factory="org.jbpm.msg.jms.JmsMessageServiceFactoryImpl" />


                              Now, I'm getting NPE in JmsMessageServiceFactoryImpl openService. It happens at line 49:

                              ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup(connectionFactoryJndiName);


                              I see that the private member connectionFactoryJndiName is initialized to 'null' and there's no method to change it to another value. Is it injected from another place? Is there some code missing here?


                              try something like this:

                              <service name="message" factory="org.jbpm.msg.jms.JmsMessageServiceFactoryImpl">
                               <field name="connectionFactoryJndiName"><string value="java:/XaConnectionFactory" /></field>
                              </service>


                              although you need to replace the jndi name as i don't know it by heart.

                              • 42. Re: MessageService and JMS
                                mteira

                                Hello again.

                                I was not able to make it work with the configuration you pasted here. But I found the code where the configuration is parsed and I think that the only way to inject fields into a factory is to declare explicitly to be a BeanInfo. Looking at the code in JbpmContextInfo constructor, while iterating over the serviceElements:

                                if (serviceElement.hasAttribute("factory")) {
                                 String factoryClassName = serviceElement.getAttribute("factory");
                                 BeanInfo beanInfo = new BeanInfo();
                                 beanInfo.setClassName(factoryClassName);
                                 serviceFactoryObjectInfo = beanInfo;
                                 } else {
                                 Element factoryElement = XmlUtil.element(serviceElement, "factory");
                                 if (factoryElement==null) {
                                 throw new ConfigurationException("element 'service' requires either a factory attribute or a factory element");
                                 }
                                 Element factoryBeanElement = XmlUtil.element(factoryElement);
                                 if (factoryBeanElement==null) {
                                 throw new ConfigurationException("element 'factory' requires either a bean or ref element");
                                 }
                                 serviceFactoryObjectInfo = objectFactoryParser.parse(factoryBeanElement);
                                 }


                                I understand that when the 'factory' attribute is present, a BeanInfo is created using the no-args constructor, and then, only the className is set. The only way to create a BeanInfo with fields to inject is to create it using the
                                public BeanInfo(Element beanElement, ObjectFactoryParser objectFactoryParser)


                                constructor. So, I've used this configuration to create the service factory:

                                <service name="message">
                                 <factory><bean class="org.jbpm.msg.jms.JmsMessageServiceFactoryImpl">
                                 <field name="connectionFactoryJndiName"><string value="java:/XAConnectionFactory"/></field>
                                 <field name="destinationJndiName"><string value="queue/JbpmCommandQueue"/></field>
                                 </bean></factory>
                                 </service>


                                As you can see, I've used the same JbpmCommandQueue as the destination for the JMS Message Service, but I was not really sure about that. I was hypothesizing that everything that the message service can generate were Command instances, so new Commands would be generated after processing the Process Instance nodes, and those Commands would be also consumed by the CmdListener MDB.

                                When I tried to send a Composite Command with (NewProcessInstanceCommand, SignalCommand) I finally got an Exception caused by:
                                org.jbpm.JbpmException: command listener bean only can handle object messages with Command's as the object.


                                So, I think I'm missing part of the picture, and perhaps there's another queue involved. Could you please explain me the whole workflow of the JMS Message Service System?

                                Best regards.

                                • 43. Re: MessageService and JMS
                                  mteira

                                  After spending some time looking at the code, I'm starting to suspect that what is missing here is a new MDB, pretty similar to the CommandListener one, to play as a consumer of the Jobs that got queued into the queue configured in the JmsMessageServiceImpl as destinationJndiName (that should be, of course, different from the one used for the CommandListener).

                                  Is this true?

                                  Regards.

                                  • 44. Re: MessageService and JMS
                                    mteira

                                    Hello.

                                    During my tests, I needed to change some config files, like hibernate.cfg.xml or jbpm.cfg.xml. For example, when I want to use an Oracle database as backend, I need to change the hibernate.cfg.xml file (that eventually gets bundled into the ear file). When I want to use the JMS based message service, I also need to setup the jbpm.cfg.xml file. I think that perhaps a good way to achieve this could be to use properties that can be overriden in the local build.properties file.

                                    But for example, when I want to use the DB based message service, I have to write, in the service tag:

                                    <service name="message"
                                     factory="org.jbpm.msg.db.DbMessageServiceFactory"/>


                                    and to use the JMS based one:

                                    <service name="message">
                                     <factory>
                                     <bean class="org.jbpm.msg.jms.JmsMessageServiceImpl">
                                     <field name="connectionFactoryJndiName">
                                     <string value="java:XAConnectionFactory"/>
                                     </field>
                                     <field name="destinationJndiName">
                                     <string value="queue/JbpmJobQueue"/>
                                     </field>
                                     </bean>
                                     </factory>
                                    </service>


                                    This seems a difficult case to be solved using build properties if we want the ant targets to be not aware of how the services are, or what parameters they need. What I want to mean is that we would need to make the ant target know that a JMS Message service needs those field names, that could be coded using properties. Perhaps we should need a target for every different kind of service.

                                    A better approach could be to have different XML excerpts, one for any kind of service and just assemble all together to generate the jbpm.cfg.xml file in build time, controlled using build properties that could be overriden.

                                    Well, perhaps all this is already solved. I'm not even sure if you understand what I'm trying to say (my english couldn't be worse), but I think that there should be a way to particularize these kind of things without need to change any file under version control.

                                    BTW. Any comment about my previous post and that hypotetic new MDB. Is it actually needed?

                                    Best Regards.
                                    --
                                    Manuel Teira