Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tomcat + CDI + Arquillian

I use Tomcat 7 together with CDI and for that I used the jee6-servlet-minimal-archetype from the Knappsack Maven Archetypes as a starting point.

Now I'd like to use Arquillian for testing the CDI beans, but even after searching for quite some time, I only found a number of problems related to the topic.

Can someone point me to a working setup (especially the right pom.xml to use) using Arquillian for CDI tests on Tomcat 7?


Edited 2012/09/11: As pointed out in a comment below, I think to get my problem solved, I need someone to help me understanding the whole setup, rather than trying to solve a specific exception at some point.

So, how must the pom.xml and the test class look like, for having a CDI bean in a tomcat 7 and being able to test it with all the injection mechanisms in both an embedded and managed container? (By the way, why is there no remote container adapter for tomcat 7 anymore as it has been for 6?)

I already tried to adapt the tomcat 6 example, but couldn't make it work on tomcat 7.

like image 262
Alexander Rühl Avatar asked Sep 08 '12 21:09

Alexander Rühl


2 Answers

Unfortunately, I haven't yet found or being told about a working example for my problem, but was able to come up with something that worked for me, which I want to show here - maybe it helps someone, since I assumed that the problem is not an exotic one and maybe someone can look over it and give me a hint in case something should be different.

/pom.xml (usable in eclipse [3.7] with a tomcat 7 [7.0.30], make sure that Project Properties/Deployment Assembly does not contain test classes/resources):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>cditomcat</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>cditomcat</name>
    <description>This pom is the base for a project using JSF2+CDI on a tomcat 7 and Arquillian for tests.</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Java EE Dependencies -->
        <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-rt</artifactId>
            <version>2.2.7</version>
        </dependency>

        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.0</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.0.2-b10</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.0.0.GA</version>
            <scope>compile</scope>
        </dependency>

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

        <!-- Test dependencies -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.arquillian.junit</groupId>
            <artifactId>arquillian-junit-container</artifactId>
            <version>1.0.0.CR5</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.shrinkwrap.container</groupId>
            <artifactId>shrinkwrap-container-tomcat-60</artifactId>
            <version>1.0.0-beta-1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.shrinkwrap</groupId>
            <artifactId>shrinkwrap-api</artifactId>
            <version>1.0.0-cr-1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.shrinkwrap</groupId>
            <artifactId>shrinkwrap-spi</artifactId>
            <version>1.0.0-cr-1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.shrinkwrap.descriptors</groupId>
            <artifactId>shrinkwrap-descriptors-api</artifactId>
            <version>1.1.0-beta-1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.shrinkwrap.descriptors</groupId>
            <artifactId>shrinkwrap-descriptors-impl</artifactId>
            <version>1.1.0-beta-1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>cditomcat</finalName>
        <testSourceDirectory>src/test/java</testSourceDirectory>

        <plugins>
            <!-- Facilitates downloading source and javadoc in Eclipse -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.8</version>
                <configuration>
                    <wtpversion>2.0</wtpversion>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>

            <!-- Ensures we are compiling at 1.6 level -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>

            <!-- Tomcat plugin for embedded tomcat -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>tomcat-maven-plugin</artifactId>
                <version>1.1</version>
                <configuration>
                    <path>/${project.build.finalName}</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>tc7-embedded</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>

            <build>
                <testResources>
                    <testResource>
                        <directory>src/test/resources</directory>
                    </testResource>
                    <testResource>
                        <directory>src/test/resources/embedded</directory>
                    </testResource>
                </testResources>
            </build>

            <dependencies>
                <dependency>
                    <groupId>org.jboss.arquillian.container</groupId>
                    <artifactId>arquillian-tomcat-embedded-7</artifactId>
                    <version>1.0.0.CR3</version>
                    <scope>test</scope>
                </dependency>

                <dependency>
                    <groupId>org.apache.tomcat.embed</groupId>
                    <artifactId>tomcat-embed-core</artifactId>
                    <version>7.0.19</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.apache.tomcat.embed</groupId>
                    <artifactId>tomcat-embed-jasper</artifactId>
                    <version>7.0.19</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.eclipse.jdt.core.compiler</groupId>
                    <artifactId>ecj</artifactId>
                    <version>3.7</version>
                    <scope>test</scope>
                </dependency>

                <!-- Provided scoped dependencies for embedded container -->
                <dependency>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-catalina</artifactId>
                    <version>7.0.29</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-coyote</artifactId>
                    <version>7.0.29</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jasper</artifactId>
                    <version>7.0.29</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                    <version>2.5</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.jboss.arquillian.container</groupId>
                    <artifactId>arquillian-container-test-spi</artifactId>
                    <version>1.0.2.Final</version>
                    <scope>test</scope>
                </dependency>

                <dependency>
                    <groupId>org.jboss.arquillian.container</groupId>
                    <artifactId>arquillian-container-spi</artifactId>
                    <version>1.0.0.CR5</version>
                    <scope>test</scope>
                </dependency>
            </dependencies>
        </profile>

        <profile>
            <id>tc7-managed</id>
            <build>
                <testResources>
                    <testResource>
                        <directory>src/test/resources</directory>
                    </testResource>
                    <testResource>
                        <directory>src/test/resources/managed</directory>
                    </testResource>
                </testResources>
            </build>

            <dependencies>
                <dependency>
                    <groupId>org.jboss.arquillian.container</groupId>
                    <artifactId>arquillian-tomcat-managed-7</artifactId>
                    <version>1.0.0.CR3</version>
                    <scope>test</scope>
                </dependency>

                <!-- Provided scoped dependencies for embedded container -->
                <dependency>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-catalina</artifactId>
                    <version>7.0.29</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-coyote</artifactId>
                    <version>7.0.29</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jasper</artifactId>
                    <version>7.0.29</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                    <version>2.5</version>
                    <scope>provided</scope>
                </dependency>

                <dependency>
                    <groupId>org.jboss.arquillian.container</groupId>
                    <artifactId>arquillian-container-test-spi</artifactId>
                    <version>1.0.2.Final</version>
                    <scope>test</scope>
                </dependency>

                <dependency>
                    <groupId>org.jboss.arquillian.container</groupId>
                    <artifactId>arquillian-container-spi</artifactId>
                    <version>1.0.0.CR5</version>
                    <scope>test</scope>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
</project>

/src/main/webapp/WEB-INF/web.xml (I still used version 2.5):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    <context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
        <param-value>true</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
    </listener>
    <resource-env-ref>
        <description>Object factory for the CDI Bean Manager</description>
        <resource-env-ref-name>BeanManager</resource-env-ref-name>
        <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
    </resource-env-ref>

</web-app>

/src/main/webapp/META-INF/context.xml (injection in Servlets, Listeners, Filters not used):

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <!-- disable storage of sessions across restarts -->
    <Manager pathname=""/>
    <Resource name="BeanManager" auth="Container" type="javax.enterprise.inject.spi.BeanManager" factory="org.jboss.weld.resources.ManagerObjectFactory"/>
</Context>

/src/main/resources/META-INF/beans.xml /src/test/resources/in-container-beans.xml (empty marker files are identically for application and test):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

/src/test/resources/in-container-web.xml (same for embedded and managed):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

    <env-entry>
        <env-entry-name>name</env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>Tomcat</env-entry-value>
    </env-entry>

    <listener>
        <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
    </listener>

    <resource-env-ref>
        <resource-env-ref-name>BeanManager</resource-env-ref-name>
        <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
    </resource-env-ref>
</web-app>

/src/test/resources/in-container-context.xml (same for embedded and managed):

<Context>
    <Resource name="BeanManager" auth="Container"
        type="javax.enterprise.inject.spi.BeanManager" factory="org.jboss.weld.resources.ManagerObjectFactory" />
</Context>

/src/test/resources/embedded/arquillian.xml (this file is for embedded only):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://jboss.org/schema/arquillian"
    xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">

    <engine>
        <property name="deploymentExportPath">target</property>
    </engine>
    <container qualifier="tomcat" default="true">
        <configuration>
            <property name="tomcatHome">target/tomcat-embedded-7</property>
            <property name="workDir">work</property>
            <property name="appBase">webapps</property>
            <property name="bindHttpPort">8889</property>
            <property name="unpackArchive">true</property>
        </configuration>
    </container>
</arquillian>

/src/test/resources/managed/arquillian.xml (this file is for managed only):

<?xml version="1.0"?>
<arquillian
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://jboss.org/schema/arquillian"
        xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">

    <container qualifier="tomcat" default="true">
        <configuration>
            <property name="jmxPort">8099</property>
            <property name="host">localhost</property>
            <property name="port">8080</property>
            <property name="user">tomcat</property>
            <property name="pass">manager</property>
        </configuration>
    </container>
</arquillian>

For managed container deployment to work, tomcat's tomcat-users.xml file has to be extended to enable the manager, e.g.:

...
<role rolename="manager-gui" />
    <role rolename="manager-jmx" />
    <role rolename="manager-script" />
    <user username="tomcat" password="manager"
        roles="manager-gui,manager-jmx, manager-script" />
...

Finally, each arquillian test class has to have a deployment method as follows (I used Servlet 2.5):

...
    @Deployment
    @OverProtocol("Servlet 2.5")
    public static WebArchive createDeployment() {
        return ShrinkWrap
                .create(WebArchive.class, "test.war")
                .addClass(MyTest.class)
                .addAsLibrary(
                        MavenArtifactResolver
                                .resolve("org.jboss.weld.servlet:weld-servlet:1.1.4.Final"))
                .addAsWebInfResource("in-container-beans.xml", "beans.xml")
                .addAsManifestResource("in-container-context.xml",
                        "context.xml").setWebXML("in-container-web.xml");
    }
...

Weld has to be packaged, which is taken from local maven repository in my case as done in the question's referenced example (edited section) by the following code:

public class MavenArtifactResolver {
    private static final String LOCAL_MAVEN_REPO =
            System.getProperty("user.home") + File.separatorChar +
                    ".m2" + File.separatorChar + "repository";

    public static File resolve(String groupId, String artifactId, String version) {
        return new File(LOCAL_MAVEN_REPO + File.separatorChar +
                groupId.replace(".", File.separator) + File.separatorChar +
                artifactId + File.separatorChar +
                version + File.separatorChar +
                artifactId + "-" + version + ".jar");
    }

    public static File resolve(String qualifiedArtifactId) {
        String[] segments = qualifiedArtifactId.split(":");
        return resolve(segments[0], segments[1], segments[2]);
    }
}
like image 71
Alexander Rühl Avatar answered Sep 21 '22 12:09

Alexander Rühl


Here's a setup that works for the Java EE certified version of Tomcat 7 (TomEE). It includes CDI and there are a handful of working Arquillian adapters:

  • http://tomee.apache.org/arquillian.html

Note that page mentions using properties to get the right port to use for sending requests to Tomcat. Ignore that. The correct approach is a field like this in your testcase:

@ArquillianResource
private URL url;

That will be the base URL of your webapp, ports and all.

like image 37
David Blevins Avatar answered Sep 21 '22 12:09

David Blevins