Creating a Maven archetype for WildFly – Part 2

In the first part (Creating a Maven archetype for WildFly – Part 1 ) we have learnt how to create a simple Maven archetype for WildFly which generates the skeleton of a Web application project with the needed dependencies and plugins. Now let’s see how we can expand a bit our archetype adding some test tooling.

Here is the initial project structure for our archetype:

├── pom.xml
├── src
│   └── main
│       └── resources
│           ├── archetype-resources
│           │   ├── pom.xml
│           │   └── src
│           │       ├── main
│           │       │   ├── java
│           │       │   └── webapp
│           │       │       ├── index.html
│           │       │       └── WEB-INF
│           │       │           └── beans.xml
│           │       └── test
│           │           ├── java
│           │           └── resources
│           └── META-INF
│               └── maven
│                   └── archetype-metadata.xml

From this point we will add a Test Java class in src/main/java and an Arquillian Test class in src/test/java

Here is our basic Test class which is a CDI Bean:

package ${package}.beans;

import javax.enterprise.context.RequestScoped;
 
@RequestScoped
public class DemoBean {
 
    public String greet(String name) {
           return "Hello "+ name;
    }
 
}

Please notice that the package name includes the auto-generated property ${package} so that the actual package for your class will be your project’s package, as decided when you use your archetype.

Next, the Test class for it:

package ${package};

import ${package}.beans.*;
 
import javax.inject.Inject;
 
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
 
import static org.junit.Assert.*;
 
@RunWith(Arquillian.class)
public class AppTest {
 
    @Inject
    private DemoBean demoBean;
 
    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class).addClass(DemoBean.class)
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }
 
    @Test
    public void should_be_deployed() {
        Assert.assertNotNull(demoBean);
    }
 
    @Test
    public void should_greet() {
    	assertEquals(demoBean.greet("Frank"),"Hello Frank");
    } 
}

As you can see, we basically test that the Bean has been injected when deployed and that the “greet” method returns the expected value.

The pom.xml in needs some adjustments to include cdi and arquillian libraries. Also we will include some profiles to run Arquillian in managed or remote mode:

<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>${groupId}</groupId>
   <artifactId>${artifactId}</artifactId>
   <version>${version}</version>
   <packaging>war</packaging>
   <name>WildFly Webapp Archetype</name>
   <properties>
      <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <version.wildfly.plugin>1.2.1.Final</version.wildfly.plugin>
      <version.failsafe.plugin>2.21.0</version.failsafe.plugin>
   </properties>
   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.wildfly.bom</groupId>
            <artifactId>wildfly-javaee7-with-tools</artifactId>
            <version>12.0.0.Final</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>
   <dependencies>
      <!-- Needed for running tests (you may also use TestNG) -->
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.jboss.arquillian.junit</groupId>
         <artifactId>arquillian-junit-container</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.jboss.arquillian.protocol</groupId>
         <artifactId>arquillian-protocol-servlet</artifactId>
         <scope>test</scope>
      </dependency>
      <!-- Import the CDI API, we use provided scope as the API is included in
              JBoss EAP -->
      <dependency>
         <groupId>javax.enterprise</groupId>
         <artifactId>cdi-api</artifactId>
         <scope>provided</scope>
      </dependency>
   </dependencies>
   <build>
      <finalName>${project.artifactId}</finalName>
      <plugins>
         <plugin>
            <groupId>org.wildfly.plugins</groupId>
            <artifactId>wildfly-maven-plugin</artifactId>
            <version>${version.wildfly.plugin}</version>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
               <source>1.8</source>
               <target>1.8</target>
               <compilerArguments>
                  <endorseddirs>${endorsed.dir}</endorseddirs>
               </compilerArguments>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.3</version>
            <configuration>
               <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
         </plugin>
      </plugins>
   </build>
   <profiles>
      <profile>
         <!-- All the modules that require nothing but JBoss Enterprise
                       Application Platform or JBoss EAP -->
         <id>default</id>
         <activation>
            <activeByDefault>true</activeByDefault>
         </activation>
      </profile>
      <profile>
         <!-- An optional Arquillian testing profile that executes tests in your JBoss EAP instance.
                    This profile will start a new JBoss EAP instance, and execute the test, shutting it down when done.
                    Run with: mvn clean verify -Parq-managed -->
         <id>arq-managed</id>
         <dependencies>
            <dependency>
               <groupId>org.wildfly.arquillian</groupId>
               <artifactId>wildfly-arquillian-container-managed</artifactId>
               <scope>test</scope>
            </dependency>
         </dependencies>
         <build>
            <plugins>
               <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-failsafe-plugin</artifactId>
                  <version>${version.failsafe.plugin}</version>
                  <executions>
                     <execution>
                        <goals>
                           <goal>integration-test</goal>
                           <goal>verify</goal>
                        </goals>
                     </execution>
                  </executions>
               </plugin>
               <plugin>
                  <artifactId>maven-surefire-plugin</artifactId>
                  <version>2.21.0</version>
                  <configuration>
                     <systemPropertyVariables>
                        <JBOSS_HOME>${env.JBOSS_HOME}</JBOSS_HOME>
                     </systemPropertyVariables>
                     <skip>false</skip>
                  </configuration>
               </plugin>
            </plugins>
         </build>
      </profile>
      <profile>
         <!-- An optional Arquillian testing profile that executes tests in a remote JBoss EAP instance.
                    Run with: mvn clean verify -Parq-remote -->
         <id>arq-remote</id>
         <dependencies>
            <dependency>
               <groupId>org.wildfly.arquillian</groupId>
               <artifactId>wildfly-arquillian-container-remote</artifactId>
               <scope>test</scope>
            </dependency>
         </dependencies>
         <build>
            <plugins>
               <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-failsafe-plugin</artifactId>
                  <version>${version.failsafe.plugin}</version>
                  <executions>
                     <execution>
                        <goals>
                           <goal>integration-test</goal>
                           <goal>verify</goal>
                        </goals>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>
</project>

As a side note, we have included also the maven-surefire-plugin to pass the JBOSS_HOME environment variable to our arq-managed profile. This is needed by Arquillian so that it can bootstrap the Application Server where it’s installed.

Arquillian will also need a definition in arquillian.xml of the Container that will be used to run the Test:

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

    <!-- Example configuration for a managed JBoss EAP instance -->
    <container qualifier="jboss" default="true">
        <configuration>
            <property name="jbossHome">${JBOSS_HOME}</property>
        </configuration> 
    </container>
</arquillian>

We are almost done. The last update needed to our project is into the archetype-metadata.xml file, so that also java classes and xml files will be included in the archetype:

<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd" 
                      name="JavaEE7 web application archetype"
    xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <fileSets>
    <fileSet filtered="true" encoding="UTF-8">
      <directory>src/main/webapp</directory>
      <includes>
        <include>**/*.jsp</include>
        <include>**/*.html</include>
        <include>**/*.xml</include>
      </includes>
    </fileSet>
    <fileSet filtered="true" packaged="true">
      <directory>src/main/java</directory>
    </fileSet>
    <fileSet filtered="true" packaged="true">
      <directory>src/test/java</directory>
    </fileSet>
    <fileSet filtered="true" packaged="false">
      <directory>src/test/resources</directory>
	<includes>
        <include>**/*.xml</include>
      </includes>
    </fileSet>
  </fileSets>
</archetype-descriptor>

Please notice the attribute packaged which, when set to true, places the source code in the package chosen by your project, as we will see in a minute. Obviously this is not wanted for xml files therefore it is set to false in the last fileSet.

Here is the final view of your archetype:

webapp-wildfly-tools
├── pom.xml
├── src
│   └── main
│       └── resources
│           ├── archetype-resources
│           │   ├── pom.xml
│           │   └── src
│           │       ├── main
│           │       │   ├── java
│           │       │   │   └── DemoBean.java
│           │       │   └── webapp
│           │       │       ├── index.html
│           │       │       └── WEB-INF
│           │       │           └── beans.xml
│           │       └── test
│           │           ├── java
│           │           │   └── AppTest.java
│           │           └── resources
│           │               └── arquillian.xml
│           └── META-INF
│               └── maven
│                   └── archetype-metadata.xml

Now build install the archetype in your local repository with:

$ mvn clean install archetype:update-local-catalog

Let’s test it! Since the archetype is in the local repository we can create a new Web application from it with:

$ mvn archetype:generate -Darchetype.interactive=false   --batch-mode -DarchetypeGroupId=org.wildfly -DarchetypeArtifactId=webapp-wildfly-tools -DarchetypeVersion=12 -DgroupId=com.example -DartifactId=demowebtools

Here is the project which has been created for you:

demowebtools/
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── DemoBean.java
    │   └── webapp
    │       ├── index.html
    │       └── WEB-INF
    │           └── beans.xml
    └── test
        ├── java
        │   └── com
        │       └── example
        │           └── AppTest.java
        └── resources
            └── arquillian.xml


Now export your JBOSS_HOME to the location where you have installed WildFly:

export JBOSS_HOME=/home/jboss/wildfly-12.0.0.Final/

Now let’s run a test with the Managed profile

$ mvn clean install -Parq-managed

This will boot the application server and the expected outcome should be:

[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 11.825 s - in com.example.AppTest
May 25, 2018 11:40:50 AM org.jboss.arquillian.core.impl.ObserverImpl resolveArguments

Much the same way you can run a Test with the remote profile against a running WildFly instance with:

$ mvn clean install -Parq-remote

Hopefully you have enjoyed this tour of Maven Archetype for WildFly!

You can download this archetype and use it from http://www.mastertheboss.com/code/webapp-wildfly-tools.zip