Building EE applications

Now that we explored all the core features of Maven, we are ready to use them together to manage the build process of Java EE applications. Usually, EE applications consist of several WAR and JAR archives, and so the Maven way to manage them is to create a multimodule Maven project.

Building WEB applications

As we have already seen in the preceding examples, and also when we spoke of WAR packaging, we have to put the web application resources (JSP files, deployment descriptors, static images, and so on) under /src/main/webapp. This is the default value for the warSourceDirectory configuration property of the Maven WAR Plugin.

In addition, we can define other web resource directories and activate resource filtering for the additional resources. We can also enable the filtering of the deployment descriptors using the filteringDeploymentDescriptors configuration property, but other resources under the /src/main/webapp default directory cannot be filtered.

Tip

It seems that only the web.xml descriptor can be filtered setting the filteringDeploymentDescriptors property to true. Other proprietary descriptors such as weblogic-web.xml or jboss-web.xml are left unaltered. The recommended way to filter web application resources is to put them in additional web resource directories.

Here is an example of how to configure the Maven WAR Plugin to enable web resource filtering:

<filters>
  <filter>src/main/filters/webapp.properties</filter>
</filters>
<plugins>
  <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
      <filteringDeploymentDescriptors>
true
</filteringDeploymentDescriptors>
      <nonFilteredFileExtensions>
        <!-- default value contains jpg, jpeg, gif, bmp, png -->
        <nonFilteredFileExtension>pdf</nonFilteredFileExtension>
      </nonFilteredFileExtensions>
      <webResources>
        <resource>
          <directory>src/main/webResources</directory>
          <filtering>true</filtering>
        </resource>
      </webResources>
    </configuration>
  </plugin>
</plugins>

Further information about the Maven WAR Plugin can be obtained invoking the Maven Help Plugin, as follows:

$ mvn help:describe -Dplugin=war -Ddetail

When we declare dependencies for a web application, we have to pay attention to the dependency scopes. As we know, all the direct and transitive dependencies resulting at the compile and runtime scopes will be included in the packaged archive. Often, we don't need to include artifacts in our WAR; we can encounter classpath problems doing this, which happens when these libraries are provided by the web application container. We have to remember to use the provided scope for these dependencies. In case of transitive dependencies, their scope should be overridden in our POM, or they can be excluded if they are not needed for the compilation of our project.

Building enterprise applications

Enterprise applications are packaged in EAR archives and can contain multiple EJB modules, WAR archives, and JAR libraries. All these artifacts must be referred to through their Maven coordinates, and some of them are usually siblings within the same multimodule Maven project.

Let's consider our transportation-project example and suppose that we want to build an EAR corresponding to the transportation-acq-ear module. This archive should contain the following:

  • The transportation-acq-ejb module
  • The transportation-acq-war module
  • All the compile and runtime dependencies needed by EJB and WAR modules
  • The application.xml descriptor

The common dependencies of EJB and WAR modules should be put in the library directory of the EAR and should not be repeated in the /WEB-INF/lib folders of the WAR modules.

We can achieve this result by just configuring the POMs of all these modules; the Maven EAR Plugin, bound by default to the package phase of the build lifecycle, will do the job and also generate the application.xml descriptor.

Suppose that the POM of the EJB module is as follows:

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.packt.examples</groupId>
        <artifactId>transportation-project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>transportation-acq-ejb</artifactId>
    <name>transportation-acq-ejb</name>
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.1</version>
        </dependency>
    </dependencies>
</project>

Suppose that the POM of the WEB module is the following. Notice that all its dependencies have the provided scope:

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.packt.examples</groupId>
        <artifactId>transportation-project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>transportation-acq-war</artifactId>
    <packaging>war</packaging>
    <name>transportation-acq-war</name>
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.1</version>
            <scope>provided</scope>
        </dependency>           
    </dependencies>
</project>

Then, we can edit the POM of the EAR module and customize the Maven EAR Plugin this way:

<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.packt.examples</groupId>
    <artifactId>transportation-project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>transportation-acq-ear</artifactId>
  <packaging>ear</packaging>
  <name>transportation-acq-ear</name>
  <description>Transportation Project Acquisition EAR</description>
  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>transportation-acq-ejb</artifactId>
      <version>${project.version}</version>
      <type>ejb</type>
    </dependency>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>transportation-acq-war</artifactId>
      <version>${project.version}</version>
      <type>war</type>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.1</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.1</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-ear-plugin</artifactId>
        <configuration>
          <displayName>Java EE Application</displayName>
          <version>6</version>
          <generateApplicationXml>true</generateApplicationXml>
          <defaultLibBundleDir>lib</defaultLibBundleDir>
          <modules>
            <ejbModule>
              <groupId>${project.groupId}</groupId>
              <artifactId>transportation-acq-ejb</artifactId>
            </ejbModule>
            <webModule>
              <groupId>${project.groupId}</groupId>
              <artifactId>transportation-acq-war</artifactId>
            </webModule>
          </modules>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

We have to note the following points:

  • The EJB and WEB modules have to be declared in the Maven EAR Plugin configuration
  • The EJB and WEB modules also have to appear among the dependencies of the EAR module, and for these dependencies, we have to specify the attribute type (with values ejb and war, respectively)
  • The dependencies of the WAR module have the provided scope, and they are reintroduced at the compile scope in the EAR module

The resulting archive will have the following structure:

Building enterprise applications

The WAR module will not contain any JAR archive, and the content of the generated application.xml descriptor will be as follows:

<application>
  <description> Transportation Project Acquisition EAR</description>
  <display-name>Java EE Application</display-name>
  <module>
    <ejb>transportation-acq-ejb-0.0.1-SNAPSHOT.jar</ejb>
  </module>
  <module>
    <web>
      <web-uri>transportation-acq-war-0.0.1-SNAPSHOT.war</web-uri>
      <context-root>/transportation-acq-war</context-root>
    </web>
  </module>
  <library-directory>lib</library-directory>
</application>

If we want to customize the context root of the WEB module, this defaults to its artifactId. We should put the <contextRoot> child element in the <webModule> element of the Maven EAR Plugin configuration, as follows:

<webModule>
  <groupId>${project.groupId}</groupId>
  <artifactId>transportation-acq-war</artifactId>
  <contextRoot>/custom-context-root</contextRoot>
</webModule>

Finally, in the case of WEB modules, the dependencies at the compile scope, as we have seen before, will be packaged in the WAR archives, but they will not be transitive dependencies of the EAR module, so they will not be duplicated in the library directory of the EAR archive.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset