11 Replies Latest reply on Aug 2, 2009 1:20 AM by Robert Moskal

    Re-using the REST facade

    Heiko Braun Master

       


      Greetings Heiko:

      Sorry to barge in on you but I've been using Andries Inzé's spring integration as the basis for a JBPM application I'm building for a client. I'd like to incorporate the reast-easy interface from the gwt-console application.

      It would be nice to use your integration layer so I can make a clean integration with the console server code. It seems it is largely a matter of putting classes like TaskManagementImpl directly on the spring context.

      Any pointers as to how you might handle this would be appreciated. I need this for a current project and would be pleased to return any accomplishments to the community.

      Regards,

      Robert


        • 1. Re: Re-using the REST facade
          Heiko Braun Master

          I am not sure if I understand you correctly. can elaborate on what you are trying to achieve?

          • 2. Re: Re-using the REST facade
            Robert Moskal Newbie

            I am creating a jbpm application that is backed by a spring context. The base for what I'm doing is here:

            http://code.google.com/p/jbpm4-spring-demo/

            I would like to use the existing gwt-console REST service to expose my spring back process engine to a ui (of my own) as well as to service applications.

            As there is now a spring integration for jbpm4, it seems this is something that many people would like to do. It would be nice to do this as elegantly as possible.

            Thanks,

            Robert

            • 3. Re: Re-using the REST facade
              Joram Barrez Master

              My idea: just point the gwt console to the same database as your Spring process engine and you get the functionality you want.

              Imo, there is no need to integrate Spring with the console (that's why the REST facade exists in the first place - to integrate technologies through a common protocol).

              • 4. Re: Re-using the REST facade
                Robert Moskal Newbie

                That was my initial idea too. But when I do that the rest server throws errors when you try to do something like just enumerate deployed processes. They are Juel errors, property not found when the Juel script engine comes across references to beans that live on the spring context.



                For the above node Juel complains it can't find nodeService3. This is just when I issue the call to list deployed proceses.

                The processEngine used by the restful api will needs access to my spring context when doing things like sending signals to my app.

                I noticed the rest server gets its processEngine from jndi (in JBPMIntegration). Perhaps if I were to somehow publish the processEngine embeded in my spring context onto java:/ProcessEngine that would do the trick.

                Thanks for your time.

                Robert

                • 5. Re: Re-using the REST facade
                  Robert Moskal Newbie

                  Sorry I for got to apply the right style to the xml:

                  <custom expr="#{nodeService3}" g="335,152,92,52" name="department">


                  • 6. Re: Re-using the REST facade
                    Joram Barrez Master

                    Ah now I see your problem.
                    That's indeed a tricky one to solve without hacking (a lot) the jbpm-console integration code. Your suggestion to push your own process engine to jndi doesn't seem so unreasonable, but I'm wondering how this easiliy could be done, since the processengine is only accessible on the JBoss server.

                    • 7. Re: Re-using the REST facade
                      Robert Moskal Newbie

                      I do see how the cleanest way to do is is to replace the jbpm jboss service with one that publishes processEngine that is embedded in my spring context. This does tie me to JBoss which is not so bad.

                      I also see a hack, which really doesn't seem so bad either. It basically involves short-circuiting your workflow engine neutral abstractions. It might even be worth it to incorporate these changes into the main code. Let me know what you think:

                      I will simply create a jar file of everything in this module gwt-console/server/server-core to avoid mucking with the code. I'll make a subclass for all the rest facades that simply add a setter for the ProcessEnginePlugin. This way I can inject that directly from the spring context. It would be nice to add that to the actual classes.

                      Then the only other thing that needs to be addressed are the classes in integration/console/src/main/java/org/jbpm/integration/console: TaskManagementImpl, ProcessEnginePluginImpl.java, etc.. The all extend from JBPMIntegration which gets the process engine from jndi:

                      ProcessEngine)ctx.lookup("java:/ProcessEngine");

                      All I need to do then is to subclass each of these and replace the constructor with one that gets the process engine from the spring context. The nice thing is that these classes are all packaged as part of jbpm-console-integration.jar.

                      Both the Facades and the JBPMIntegration integration classes will live on the spring framework. I'm not sute about the plugin stuff, but this will get me a free rpc layer for my app. I'll burn that bridge when I come to it.

                      Now as far as I can tell, to simplify this integration all thats' needed is:

                      All of the facades in server-core org.jboss.bpm.console.server need a public setter for ProcessEnginePlugin.

                      A maven task goal needs to be added to the pom file that will create a jar file for server-core.

                      Add a constructor to all the classes descending from JBPMIntegration that accepts a process engine.


                      You know the code well, if you have time let me know if I've missed anything.

                      If you think it is a reasonable idea, I'd be happy to help make the changes.


                      Thanks and regards,

                      Robert



                      • 8. Re: Re-using the REST facade
                        Heiko Braun Master

                         


                        All of the facades in server-core org.jboss.bpm.console.server need a public setter for ProcessEnginePlugin.

                        A maven task goal needs to be added to the pom file that will create a jar file for server-core.

                        Add a constructor to all the classes descending from JBPMIntegration that accepts a process engine.


                        That's nonsense. The integration layer does lookup the process engine from JNDI. Simply bind it to JNDI from your spring context and you are done. The same applies to running in tomcat and other containers.

                        • 9. Re: Re-using the REST facade
                          Robert Moskal Newbie

                          It is a bit more complicated. I forgot java chains constructors so I needed to touch the source for JBPMIntegration too. That and ProcessManagementImpl isn't a class public so I had to change that.

                          Making the above changes and loading the classes onto the spring context of my web application, got the REST api integrated into my application. All in all in took about an hour. However, I do see that I would have to do this with all the other plugins like form and graph. So I figure I'd better learn to love the jndi context again.

                          The integration this way is going pretty well. I just bind the processEngine on the Spring context to the jndi. I'm having some trouble understanding what the role of "UserTransaction" on the jndi context is.

                          tx = (UserTransaction)ctx.lookup("UserTransaction")

                          If I try to enumerate deployed processes for example I get a "javax.naming.NameNotFoundException: Name [UserTransaction] not bound" exception.

                          It seems that some of the integration code is dependendent on this. I think that if I deploy to jboss JBoss AS this is provided to me. I will test this. But what about if I want to deploy to tomcat or Jetty?

                          Any pointers would be greatly appreciated.


                          Thanks and regards,

                          Robert Moskal.

                          • 10. Re: Re-using the REST facade
                            Robert Moskal Newbie

                            I've gotten a bit farther so kindly ignore the last post. Using JOTM and the minimal spring JNDI implementation I bind the processEngine and the UserContext:

                             SimpleNamingContextBuilder builder = new builder.bind("java:/ProcessEngine",
                            builder.bind("UserTransaction", tx.getUserTransaction());
                            builder.activate();


                            All my JPM interaction works fine when I work directly with the processEngine embedded in my Spring context. If I write I little unit test where I simply instantiate ProcessManagement and try to retrieve a list of deployed processes it works just fine:

                            ManagementFactory factory = ManagementFactory.newInstance();
                            ProcessManagement service = factory.createProcessManagement();
                            List<ProcessDefinitionRef> procs = service.getProcessDefinitions();
                            assertNotNull(procs);


                            But if instead I try to get a deployed process like so:

                            ProcessInstanceRef proc = service.getProcessInstance("Pipeline_3.one-shot11");
                            assertNotNull(proc);



                            I get an error in org.jboss.bpm.console.server.util.InvocationProxy, right at the line where the proxy method is invoked. Perhaps someone could tell me what might be different. The root exception says that "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here". I don't see a big difference between the two methods in ProcessManagementImpl.

                            The stack trace follows:

                            java.lang.RuntimeException: Unexpected invocation exception: null
                             at org.jboss.bpm.console.server.util.InvocationProxy.invoke(InvocationProxy.java:80)
                             at $Proxy3.getProcessInstance(Unknown Source)
                             at com.bluesky.skyline.workflow.integration.ConsoleIntegrationTest.testProcessDelpoy(ConsoleIntegrationTest.java:151)
                             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 junit.framework.TestCase.runTest(TestCase.java:168)
                             at junit.framework.TestCase.runBare(TestCase.java:134)
                             at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
                             at junit.framework.TestResult$1.protect(TestResult.java:110)
                             at junit.framework.TestResult.runProtected(TestResult.java:128)
                             at junit.framework.TestResult.run(TestResult.java:113)
                             at junit.framework.TestCase.run(TestCase.java:124)
                             at junit.framework.TestSuite.runTest(TestSuite.java:232)
                             at junit.framework.TestSuite.run(TestSuite.java:227)
                             at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)
                             at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
                             at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
                             at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
                             at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
                             at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
                             at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
                            Caused by: java.lang.reflect.InvocationTargetException
                             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.jboss.bpm.console.server.util.InvocationProxy.invoke(InvocationProxy.java:64)
                             ... 22 more
                            Caused by: org.jbpm.pvm.internal.wire.WireException: couldn't initialize object 'org.jbpm.pvm.internal.repository.RepositorySessionImpl': No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
                             at org.jbpm.pvm.internal.wire.descriptor.ObjectDescriptor.initialize(ObjectDescriptor.java:233)
                             at org.jbpm.pvm.internal.wire.WireContext.performInitialization(WireContext.java:537)
                             at org.jbpm.pvm.internal.wire.WireContext.initialize(WireContext.java:499)
                             at org.jbpm.pvm.internal.wire.WireContext.create(WireContext.java:453)
                             at org.jbpm.pvm.internal.wire.WireContext.create(WireContext.java:441)
                             at org.jbpm.pvm.internal.wire.WireContext.get(WireContext.java:421)
                             at org.jbpm.pvm.internal.wire.WireContext.get(WireContext.java:331)
                             at org.jbpm.pvm.internal.wire.WireContext.get(WireContext.java:707)
                             at org.jbpm.pvm.internal.env.BasicEnvironment.get(BasicEnvironment.java:151)
                             at org.jbpm.pvm.internal.env.BasicEnvironment.get(BasicEnvironment.java:142)
                             at org.jbpm.pvm.internal.env.Environment.getFromCurrent(Environment.java:200)
                             at org.jbpm.pvm.internal.env.Environment.getFromCurrent(Environment.java:189)
                             at org.jbpm.pvm.internal.model.ExecutionImpl.getProcessDefinition(ExecutionImpl.java:1096)
                             at org.jbpm.integration.console.ModelAdaptor.adoptExecution(ModelAdaptor.java:69)
                             at org.jbpm.integration.console.ProcessManagementImpl.getProcessInstance(ProcessManagementImpl.java:208)
                             ... 27 more
                            Caused by: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
                             at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
                             at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:622)
                             at org.jbpm.pvm.internal.wire.descriptor.HibernateSessionDescriptor.construct(HibernateSessionDescriptor.java:73)
                             at org.jbpm.pvm.internal.wire.WireContext.construct(WireContext.java:473)
                             at org.jbpm.pvm.internal.wire.WireContext.create(WireContext.java:452)
                             at org.jbpm.pvm.internal.wire.WireContext.create(WireContext.java:441)
                             at org.jbpm.pvm.internal.wire.WireContext.get(WireContext.java:421)
                             at org.jbpm.pvm.internal.wire.WireContext.get(WireContext.java:331)
                             at org.jbpm.pvm.internal.wire.WireContext.get(WireContext.java:707)
                             at org.jbpm.pvm.internal.wire.descriptor.ObjectDescriptor.autoWire(ObjectDescriptor.java:294)
                             at org.jbpm.pvm.internal.wire.descriptor.ObjectDescriptor.initialize(ObjectDescriptor.java:225)
                             ... 41 more




                            • 11. Re: Re-using the REST facade
                              Robert Moskal Newbie

                              Just a quick followup, I was able to get the above tests to run by swapping out dotm for atomikos. And then by wrapping the test in a transaction template:

                              transactionTemplate = new TransactionTemplate((PlatformTransactionManager) applicationContext.getBean("transactionManager"));


                              ProcessInstanceRef proc = (ProcessInstanceRef) transactionTemplate.execute(new TransactionCallback() {
                              
                               public Object doInTransaction(TransactionStatus status) {
                               ManagementFactory factory = ManagementFactory.newInstance();
                               ProcessManagement service = factory.createProcessManagement();
                               return service.getProcessInstance("Pipeline_3.one-shot11");
                              
                               }
                               });
                              
                               assertNotNull(proc);


                              It would not work with dotm even with the transaction. I think the difference was the fact that atomikos has an XA data source.