Dynamic deploy of process definitions with access to a different process application Java Delegates / CDI beans


#1

Hi,
I am using Camunda 7.6.0 with Wildfly 8 (we will shortly switch to Wildfly 10) with JavaEE integration.
I have a process application containing some processes that access some Java Delegates and some CDI beans (using CDI aware expressions) and everything works fine until here.

I am working on a new feature to allow the users to dynamically deploy process definitions at runtime. I need these dynamically deployed processes to access the Java Delegates and the CDI beans available in my process application.

I tried to deploy them as separate deployments using the RepositoryService java API, but when I start the processes from the Cockpit, neither the Java Delegates nor the CDI beans referenced in expressions can be found.
If I start the processes from within my process application, the Java Delegates are found but the CDI beans referenced in expressions are still not.

I know that the normal approach would be to use war archives and deploy everything as process applications, but it would be over complicated to implement a dynamic solution for it and it will force my application to authenticate on Wildfly as an admin user.

Is it possible to dynamically deploy/undeploy new process definitions at runtime inside the process application deployment that I already have? This way, all the Java Delegates and the CDI beans will be found correctly.
Or is there another simple approach I can use?

I was also thinking to deploy all my Java Delegates / CDI beans as Wildfly modules and add them as a dependency to the Camunda Engine module, but I am not sure it will work and it is a kinda “dirty” solution in my opinion.


#2

Though I don’t have an answer - I also use CDI on WildFly 10+.

Did the logs showing this error originate from Weld or directly via Camunda? Could you share a “caused by” section?


#3

Hi Gary, thanks for the reply.

I did some further testing. I am creating a new deployment at runtime using the RepositoryService java API that includes only a process definition (no classes). This process definition references the Java Delegates and the CDI beans of my main process application (deployed as a WAR in Wildfly 8).

The CDI beans are never found and the exception is at Camunda level:

11:20:24.507 SPMGR> Caused by: org.camunda.bpm.engine.impl.javax.el.PropertyNotFoundException: Cannot resolve identifier ‘dates’
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.juel.AstIdentifier.eval(AstIdentifier.java:83)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.juel.AstMethod.invoke(AstMethod.java:79)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.juel.AstMethod.eval(AstMethod.java:75)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.juel.AstEval.eval(AstEval.java:50)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.juel.AstNode.getValue(AstNode.java:26)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.juel.TreeValueExpression.getValue(TreeValueExpression.java:114)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.delegate.ExpressionGetInvocation.invoke(ExpressionGetInvocation.java:36)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.delegate.DelegateInvocation.proceed(DelegateInvocation.java:54)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.delegate.DefaultDelegateInterceptor.handleInvocationInContext(DefaultDelegateInterceptor.java:87)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.delegate.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:59)
11:20:24.507 SPMGR> at org.camunda.bpm.engine.impl.el.JuelExpression.getValue(JuelExpression.java:55)
11:20:24.507 SPMGR> … 139 more

Java Delegates for asynchronous service tasks are not found (I get a ClassNotFound exception, since the ClassLoader used by Camunda in this case is the jboss Wildfly module classloader).
Java Delegates for synchronous service tasks are executed only if I am starting a process instance from within my process application where the Java Delegates are, but at the first asynchronous task I have the ClassNotFound problem again (since asynchronous tasks are executed by the Camunda Job Executor).

I don’t know what I can do in order to achieve the functionality I need. Is dynamic creation and deployment of WARs on Wildfly the only solution? I would avoid it, since it really is over complicated. How can I create a war artifact on the fly containing the classes of a JavaEE application? Do I need to have access on a Nexus repository in order to retrieve the jar containing the classes? Then I have to authenticate on Wildfly as an admin user in order to do automatic deployment.

Can you suggest a simpler way to implement the dynamic deployment functionality that I need for my application, please?


#4

I am thinking that basically what I would like to achieve is automatic deployment at runtime of a new process application.
That would solve my problem, since I can create a new process application setting the CDI-aware expression resolver and setting as classpath the one of my JavaEE web application containing all the Java Delegates and CDI beans.

The problem is: how can I do that? I am guessing that in order to do it I have to do the same thing done by the Camunda Wildfly subsystem when a new WAR containing a processes.xml resource inside is deployed on Wildfly. When that happens, the subsystem is deploying a new process application automatically for you.

Do you think that the approach could work?

I found this class:
https://github.com/camunda/camunda-bpm-platform/blob/master/distro/wildfly/subsystem/src/main/java/org/camunda/bpm/container/impl/jboss/deployment/processor/ProcessApplicationDeploymentProcessor.java

but the code looks kinda complicated to understand.
Do you think that it could work to do something like that at web application level? Or can it be done only by a Wildfly subsystem?

Thanks in advance,
Giorgio


#5

I also ran into this problem when I was trying to break apart a great big maven project into something more manageable. The CDI named java-beans just were not seen by various, independently deployed components.

Other folks ran into the same sort of issue. @Adam_Klima also mentioned the issue in EL expressions.

A work-around, posted to this forum, mentioned using an Initialcontext() lookup.

I had this noted as a pending work-around.


#6

Hi Gary,
thanks for your answer and for the link to the workaround.

Unfortunately I don’t think I can use the deployment architecture described in the workaround, since I need to dynamically deploy my processes and the root problem will still be the same: I cannot dynamically deploy classes at runtime using Camunda java API, not even the ones needed for the lookup (unless I dynamically deploy wars on Wildfly, which I am trying to avoid).

But I probably can try to use a slightly different deployment architecture: implement a Wildfly module containing a sort of dispatcher that is able to invoke my CDI beans / EJBs using the lookup as you suggested (or I can also do it via a REST client and keep the transactions separated for asynchronous tasks - so I will avoid remote EJBs).
Then I might try to let the camunda-engine Wildfly module depend from this dispatcher module (changing the dependencies in the module.xml file): this way every process application (and the Camunda Job Executor for asynchronous tasks) should be able to invoke my dispatcher.
I am not sure it will work, but I can give it a try.

Do you think it is a good approach? Can you see some potential issues with this architecture?


#7

Quick points… pending deadline this Thur. is crimping my time.

  • “avoid EJB binding” - yes. I personally prefer the SCA pattern (available in SwitchYard - though slightly off-standard). Works well on Websphere - not sure about Wildfly since, at this level, clients tended to lean this way. More importantly, not sure the SCA pattern has much relevance these days.

  • ReST integration - though I like the flexibility provided by loose coupling, keep in mind connection overhead. This becomes critically important if handling significant event communication. For high-performance requirements, I use HTTP connection pooling. But, this only shaves a few hundred milliseconds in cost per each. It adds up though if you’re “batching” thousands of event messages… requiring a reconnect per each.

You mentioned ProcessApplicationDeploymentProcessor.java. I haven’t had a chance to review, but I’d start there. The goal is to keep the design within Camunda’s technical “envelop” to avoid a situation where your system becomes technically orphaned via advances within the BPM-engine.

Please take my recommendations with some skepticism - I don’t have much free time this week… therefore couldn’t spend sufficient time looking at various solutions/workarounds (particular interested in Camunda’s source-code).


#8

Hi Gary, thanks a lot for your recommendations.
I can see your point: to keep the design within Camunda’s technical “envelop”.

Unfortunately I don’t have a lot of time either now, I am now stuck on another work. But I will definitely come back on this in (hopefully) a couple of weeks and I’ll let you know what I will try and the results of it.


#9

This problem appears to be a bug. I ran across some discussion specific to Weld and Wildfly. However, it should be patched by now.

I might be running into this annoyance when testing CDI references from multiple modules. And, noted the same sort of issue with Apache Camel. But, there are workarounds.

see: (example)
Wildfly camel issues

A search on “wildfly multi-module weld BeanManager” finds general discussion on the issue.

Wildfly v10 CDI Reference/documentation -
Using CDI Beans from outside the deployment

I haven’t specifically checked Camunda’s source-code. But, this may require at look how Camunda references/loads CDI beans.


#10

After a long time working on other things, I finally could go back on this problem and I solved it using remote EJBs.
Please find below some more details for future references.

The architecture that I adopted on top of the Camunda 7.6 wildfly 8 distribution is the following:

  1. my-application:
    My JavaEE application containing all the business logic that can be executed by service tasks. This business logic is also exposed via remote EJBs.
    This application (as I was already mentioning in the other posts) gives the functionality to the end users to “hot-deploy” new process definitions at runtime.

  2. my-application-client:
    A JavaSE module containing a client to the remote EJBs exposed by “my-application”.
    This is deployed as a Wildfly module, together with the “camunda-engine” Wildfly modules. This way, the Classloader used by the “camunda-engine” module at runtime will always have access to the classes inside “my-application-client”.

When a user deploys a process using the API exposed on “my-application”, under the hood I use the Camunda java API to deploy a process definition: this (as I was mentioning in the other posts) will deploy only the process definition, but unfortunately not the classes.
But with the architecture that I described above (and that I put in place and tested with success) this is not a problem anymore, as long as all java classes referenced in the process definition (java delegates, listeners, etc.) are pointing to classes contained inside “my-application-client”. This will now always work at runtime since the client is deployed as a dependency of the “camunda-engine”.

This way you can invoke all “my-application” business logic (exposed via remote EJB) also from hot-deployed processes, using “my-application-client” as entry point.

I hope this could help somebody.
I am not having problems so far with this architecture, but please let me know if you see something wrong about it or maybe something I haven’t considered.