cancel
Showing results for 
Search instead for 
Did you mean: 

Issue with EL when deploying Activiti webapp in Tomcat 6.0.x

cstettler
Champ in-the-making
Champ in-the-making
Hi all,

I see an issue with integrating the Activiti engine into a web app that should run in an out-of-the-box Tomcat 6.0.x due to a conflict with different EL versions and a compile time dependency to EL 2.2:

- Activiti includes juel which already contains the EL 2.2 in its jar (how messy …)
- Tomcat includes the EL 2.1 in its shared lib directory

Now, the ExpressionManager uses a call to ExpressionFactory.newInstance() for creating an expression factory. This API is only available since EL 2.2, but as the EL API is part of the shared libs taken by the tomcat standard class loader, the EL 2.1 takes precendence. Therefore, one gets the following exception when deploying a web app that configures an Activiti process engine:

java.lang.NoSuchMethodError: javax.el.ExpressionFactory.newInstance()Ljavax/el/ExpressionFactory;
   at org.activiti.engine.impl.el.ExpressionManager.<init>(ExpressionManager.java:55)
   at org.activiti.engine.impl.cfg.ProcessEngineConfiguration.<init>(ProcessEngineConfiguration.java:164)
   at org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean.<init>(ProcessEngineFactoryBean.java:51)

I noticed that the Tomcat included in the activit distro does no longer contain the EL library in the lib directory. To me, it looks as if Activiti is not able to run in an out-of-the-box tomcat due to this EL version conflict. In my opinion, this a major issue as in a managed environment, deleting shared libraries from an application server is for sure not an option.

In my opinion, we should stick to EL 2.1 so Activiti is able to run in a Tomcat 6.0.x (and not only in Tomcat 7.x). More general, we should define what version of the JavaEE specs we want to support (e.g. EL 2.1 is part of JavaEE 5, EL 2.2 is part of JavaEE 6).

Any comments/thoughts/help on that topic?

Thank you & regards,
Christian
9 REPLIES 9

cstettler
Champ in-the-making
Champ in-the-making
Addendum: the stacktrace shown above only appears after having excluded the juel dependency (due to the contained EL classes) from the web app class path. If the juel dependency is kept in the web app, the following exception appears due to the EL class version conflict:

java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/catalina/loader/WebappClassLoader) of the current class, com/sun/faces/config/ConfigureListener, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature
at com.sun.faces.config.ConfigureListener.registerELResolverAndListenerWithJsp(ConfigureListener.java:581)
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:212)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3972)

tombaeyens
Champ in-the-making
Champ in-the-making
any idea how hard it would be for us to:
1) use EL 2.1 only.  what exactly would need replacement?
2) fix the library dependency problem in juel.  what juel version would we need?  does it also contain the uel api's?  would we have to rip out the api from the juel jar, or are there other solutions?

tombaeyens
Champ in-the-making
Champ in-the-making
(my question was not only directed to Christian, but to the whole community in general 🙂 )

jbarrez
Star Contributor
Star Contributor
If I remember correctly, the Juel library used to be distributed as juel-api and juel-impl in the past.

I checked and it seems like the juel jar in the maven repo is an all-in-one jar.
However, when you download from the website, you can select juel-api and juel-impl separatly.

So one solution could be to upload the juel jars to our own repo.

From the JUEL docs:

- The JUEL distribution contains three basic jars: juel-api-2.2.x.jar includes only
  the api classes, whereas juel-impl-2.2.x.jar includes only the implementation
  classes; juel-spi-2.2.x.jar contains no classes: it can be used to force JUEL's
  expression factory to be taken when using ExpressionFactory.newInstance(…).

- Finally, juel-2.2.x.jar combines the contents of juel-api, juel-impl and juel-spi:
  juel-2.2.x.jar = juel-api-2.2.x.jar + juel-impl-2.2.x.jar + juel-spi-2.2.x.jar

cstettler
Champ in-the-making
Champ in-the-making
After a few hours of investigation and a spike based on Activiti 5.0 beta 2, we suggest the following approach for dealing with EL in Activiti:

  • Activiti should only have dependencies on EL 2.1 (that is javax.el:el-api 1.0 Maven artifact)

  • Activiti should use a specific strategy for resolving the ExpressionFactory implementation to be used (consistently in all places):
    • Try to invoke the EL 2.2 ExpressionFactory.newInstance() API via reflection (to avoid compile-time dependency to EL 2.2). If the container (e.g. Tomcat 7) supports EL 2.2, the EL 2.2. lookup strategy is used (javax.el.ExpressionFactory, JVM properties, system property, default implementation).

    • If the ExpressionFactory.newInstance() method cannot be found, the strategy should (at least) look for a javax.el.ExpressionFactory service file that can be used to specify a custom ExpressionFactory implementation, as supported by EL 2.2. If that file (META-INF/services/javax.el.ExpressionFactory) can be found, the specified implementation is used, even with EL 2.1.

    • Otherwise, Activiti should create a de.odysseus.el.ExpressionFactoryImpl instance via reflection (to avoid compile-time dependency to juel-impl)
  • In the activiti-root POM, Activit should only define javax.el:el-api 1.0 (which is EL 2.1) and de.odysseus.juel:juel-impl 2.2.1 in the dependency management section, both with scope "provided". Both dependencies are then actually used in the activiti-engine and activiti-engine-examples modules with scope "test" for running the tests. juel-impl 2.2.1 itself is an EL 2.2 implementation, but also works with EL 2.1 (i.e. can be used as an implementation of the EL 2.1 API)
Important to note is that the juel:juel-impl jar in the JBoss Maven repository is not "clean", e.g. it contains both the EL 2.2 API and the javax.el.ExpressionFactory service file. As a consequency, no custom ExpressionFactory implementation can be provided by an application (see below) in a safe, deterministic way, as then, multiple javax.el.ExpressionFactory service files would exist on the class path. Therefore, the de.odysseus.juel:juel-impl dependency must be used (see above), which is - unfortunately - not available from any public Maven repository, so it has to be uploaded to e.g. the Activiti Maven repo at Alfresco (I can provide the jars, if needed).

With this approach, Activiti runs in both an out-of-the-box Tomcat 6 and Tomcat 7. In addition to this, this approach allows for configuring a custom ExpressionFactory instance via the javax.el.ExpressionFactory service file in both containers in the same way, which might be needed to workaround some JSF issues with EL (we had to do this as we are about to integrate Activiti as an engine into a JSF application). Also, in both containers, the JUEL ExpressionFactory can be used, if required, but Activiti also runs without JUEL at all (i.e. only with the Jasper EL implementation of Tomcat 6 and 7).

As a drawback/consequence, the JuelScriptEngine(Factory) (the code that bridges the JSR 223 to JUEL) needs to be re-written based on EL 2.1, as the current implementation used in Activiti is not using the custom lookup strategy described above, but is hardcoded to use the EL 2.2 API (as we already implemented this in our spike, that could be used as a starting point).

Please get back to me with your comments. It would be great if we could resolve this issue for the next beta release. Let me know if I can be of any further help here.

frederikherema1
Star Contributor
Star Contributor
Christian,

First of all, thanks four your very valuable input. I just introduced resolving of the ExpressionFactory, http://fisheye.codehaus.org/changelog/activiti/?cs=688, although still with compile dependency to juel-api -> EL 2.2.
I will definitely use reflection instead of invoking and remove the dependency to juel-api and use el 1.0 instead, nice one!

Doesn't falling back to 'de.odysseus.el.ExpressionFactoryImpl' when all other steps fail, just throw an ClassNotFoundException? I would presume, if the "de.odysseus.juel:juel-impl" jar is on the classpath and contains '/META-INF/services/javax.el.ExpressionFactory', the class would be found at the first step of resolving when using EL 2.1.

I'm really interested to see how you approach the JuelScriptEngine issue.

frederikherema1
Star Contributor
Star Contributor
Important to note is that the juel:juel-impl jar in the JBoss Maven repository is not "clean", e.g. it contains both the EL 2.2 API and the javax.el.ExpressionFactory service file. As a consequency, no custom ExpressionFactory implementation can be provided by an application (see below) in a safe, deterministic way, as then, multiple javax.el.ExpressionFactory service files would exist on the class path. Therefore, the de.odysseus.juel:juel-impl dependency must be used (see above), which is - unfortunately - not available from any public Maven repository, so it has to be uploaded to e.g. the Activiti Maven repo at Alfresco (I can provide the jars, if needed).

The juel-impl jar we use (juel:juel-impl, from alfresco nexus, not sure where it is mirrored from) doesn't contain any javax.el.* classes, only de.oddysseus.* and the service file in /META-INF/services/. Or do you mean that the de.odysseus.juel:juel-impl doesn't contain a service-file?

cstettler
Champ in-the-making
Champ in-the-making
The juel-impl jar we use (juel:juel-impl, from alfresco nexus, not sure where it is mirrored from) doesn't contain any javax.el.* classes, only de.oddysseus.* and the service file in /META-INF/services/. Or do you mean that the de.odysseus.juel:juel-impl doesn't contain a service-file?

Indeed, the "clean" juel-impl.jar from the juel download does neither contain the javax.el classes nor the javax.el.ExpressionFactory file in /META-INF/services/. The javax.el classes are contained in the juel-api.jar, the service file in the juel-spi.jar, so this approach is clean. In the JBoss repo, the juel-impl.jar contains "too much".

frederikherema1
Star Contributor
Star Contributor
okay, I see. That explains alot Smiley Wink thanks