Using CDI in tomcat's DataSourceRealm

Previous Topic Next Topic
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Using CDI in tomcat's DataSourceRealm

Karel Geiregat
Dear tomcat users

Before starting with a difficult problem, I want to tell about the current
system / design.

My company's server is a tomcat version 7.0.54. We are using Maven to setup
the project and the deployment. The server is set as a 3-node tree, one
"Base" and two branches A and B, each providing their own website and
If A and B shares same functionality on eg customer data, then the code can
be found in "Base". By this, code is being reused and has improved
maintenance. But A and B shares some functionalities that are almost
similar except some additional features/tasks done when visiting a servlet.
For that, CDI is introduced. We have enabled CDI by providing the required
WELD plugin as a dependency in Base's pom.xml file (and ofc configured
Beans.xml with classes that has "@Alternative annotation)

>   <groupId>org.jboss.weld.servlet</groupId>
>   <artifactId>weld-servlet</artifactId>
> </dependency>

The CDI works fine if you visit a servlet page, it does the job. It works
at the server where A operates and another server where B operates. The
authentication of users is developed in Base, in a class that extends from
DataSourceRealm (more specifially
" org.apache.catalina.realm.DataSourceRealm " ) that returns a Principal

Now comes the question: We want to introduce some actions that happens
right after the user is being authenticated. So, when an user logs in, a
set of login-actions are executed to handle some tasks (a simple example is
a login count. But we have more advanced actions) once the user is
authenticated. So after authentication, a Principal is returned from the
parent. If it's not null (= "user is authenticated"), then execute the
actions. Then return the Principal instance. But the problem is ... the
actions differs from A and B. So, using CDI is a logical solution here.
However, when deploying and restarting to tomcat, we are getting HTTP 500
errors after authenticating users. The message is
"javax/enterprise/context/spi/Contextual" (part of CDI implementation)
cannot be found. It's from a .jar file, named as cdi-api-1.2. But it could
not be found. Here below is the output on localhost

java.lang.NoClassDefFoundError: javax/enterprise/context/spi/Contextual
>  org.apache.catalina.authenticator.FormAuthenticator.authenticate(
>  org.apache.catalina.authenticator.AuthenticatorBase.invoke(

To figure out if tomcat is really loading this jar file, we have added
"-verbose:class" in the JAVA_OPTS. One of the output is

> [Loaded javax.enterprise.context.spi.Contextual from file:/C:/dev/

that means that the required class file should be found because the
required Contextual class is inside the provided jar file. As mentioned,
the CDI implementation works fine if you visit a servlet that uses CDI. Yet
tomcat couldn't find it in the DataSourceRealm (which is a different
container I think). Here below is a part of the Base pom.xml file where a
jar file is provided to the datasourcerealm. Before authentication, we are
also doing some actions which requires those class files. Both
ILoginHandler and IActionHandler are part of the CDI implementation to run
some tasks after the login


>     <groupId>org.apache.maven.plugins</groupId>
>     <artifactId>maven-jar-plugin</artifactId>
>     <version>2.3.2</version>
>     <configuration>
>         <outputDirectory>../jars</outputDirectory>
>     </configuration>
>     <executions>
>       <execution>
>             <id>datasource</id>
>             <phase>package</phase>
>             <goals>
>                 <goal>jar</goal>
>             </goals>
>             <configuration>
>                 <archive>
>                     <index>true</index>
>                     <manifest>
> <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
>                     </manifest>
>                 </archive>
>                 <classifier>datasource</classifier>
>                 <includes>
>                     <include>com/base/core/security/*</include>
>                     <include>com/base/core/Contact*</include>
>                     <include>com/base/core/Queries*</include>
>                     <include>com/base/core/conf/*Configuration*</include>
>                     <include>com/base/core/conf/BeanHandler*</include>
>                     <include>com/base/core/net/ServletListener*</include>
>                     <include>com/base/core/</include>
>                     <include>**/META-INF/beans.xml</include>
> <include>com/base/core/actionhandlers/handlers/ILoginHandler</include>
> <include>com/base/core/actionhandlers/actions/IAction</include>
>                 </includes>
>             </configuration>
>         </execution>
>     </executions>
> </plugin>

When checking the datasource jar file, it contains the required files as
defined here above. The problem is that the external jars aren't loaded in
the DataSourceRealm while it is in tomcat's simple servlet realm. It's only
during the authentication process that the CDI fails.

What I have tried:
Searching for a bottle in google's ocean. (I even read many of Bauke
Scholtz's (AKA BalusC) blog posts and SO answers.

Making the jar executable (why not?) by adding those two lines in the same
pom.xml file

> <classpathPrefix>/WEB-INF/lib/</classpathPrefix>

dropped the jars in tomcat's /lib folder.

So ... does someone have implemented the same feature or even injected a
third party library (most examples I've seen are database connectors).. I
was just asking this myself when I wrote this mail: Is it possible to use
CDI in tomcat's DataSourceRealm?
How can I ensure that the external jars are being loaded in so that the CDI
works when authenticating an user.

- KG