AVIO Consulting

Building BPM and ADF Applications with Maven – Part 3 – Building the EAR

Oct 4, 2012 | BPM

In Part 1 of this series we imported JDeveloper libraries into our Maven repository and in Part 2 we built a WAR file for our ADF project using Maven.  In Part 3, we will now take one or more of these WAR files and package them into an EAR file for deployment.  Before we start looking at the pom.xml for the EAR build, you should know that, unlike JDeveloper, Maven defines the EAR as a separate project.  Normally, you would keep your EAR level artifacts in this project, but in the case of JDeveloper and ADF the EAR level artifacts are kept in the application folder.

Setting up the EAR Project

The first thing you will need to do is to create the EAR project structure.  This is really just another folder within your JDeveloper application that contains the pom.xml we will create.  I usually name these the same as my view project with -ear appended for example, sample-project-view-ear.

Standard POM Information

The first information we will put in our pom.xml is the very standard as you can see below.  The packaing type is ear and following the naming standard we have used I have defined a base.name property and then just appended -ear to the end of it for this artifact id. 

 

<project http://maven.apache.org/POM/4.0.0″>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/xsd/maven-4.0.0.xsd“>

  <parent>

    <groupId>com.avioconsulting.bpm</groupId>

    <artifactId>sample-project</artifactId>

    <version>1.0.0.0-SNAPSHOT</version>

  </parent>

  <modelVersion>4.0.0</modelVersion>

  <groupId>com.avioconsulting.bpm</groupId>

  <artifactId>${base.name}-ear</artifactId>

  <version>1.0.0.0-SNAPSHOT</version>

  <packaging>ear</packaging>

  <name>${base.name}-ear</name>

  <description>Sample Project – ADF Interface EAR</description>

  <properties>

    <base.name>sample-project-view</base.name>

  </properties>

Dependencies

We now need to declare our depenencies.  In our case, we have no libraries we are dependent on at the EAR level so our only dependency is our WAR project.  Below is how I have declared a dependency on the WAR file of the same version as our EAR.

 

  <dependencies>

    <dependency>

      <groupId>${project.groupId}</groupId>

      <artifactId>${base.name}</artifactId>

      <version>${project.version}</version>

      <type>war</type>

    </dependency>

  </dependencies>

Build Configuration

The build configuration for the EAR is where things start to get more complicated.  There are five items we need to account for in our build configuration:

  1. There are resources in the .adf folder at the application level that need to be placed in the adf folder within the EAR.
  2. The source files and resources in the src folder at the application level that need to be put in the EAR.
  3. The context root of the WAR file should be set correctly.  In this case, we want a version specific context root.
  4. A jar file named adf-loc.jar is required to put the adf folder within the EAR on the classpath.
  5. JDeveloper/ojdeploy modify the adf-config.xml file during packaging (at least for BPM applications).  We need to emulate these same changes.
Adding Resources from the .adf folder
This first section of our build configuration handles the .adf folder.  It sets it up as a resource location that is relative to our EAR project.  We also set the output directory so the resources are placed in the proper location in the EAR:
    <build>
    <outputDirectory>${project.build.directory}/${project.build.finalName}/adf</outputDirectory>
    <resources>
      <resource>
        <directory>../.adf</directory>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

 

Add the src directory and setting context roots
Next, we configure the maven-ear-plugin to point to the application level src directory.  We also add one webModule section for each WAR file we are dependent upon.  Here we define the context root that we want to use for that WAR file.  In our case, it includes the version number.

 

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-ear-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <version>5</version>
          <defaultLibBundleDir>lib</defaultLibBundleDir>
          <earSourceDirectory>../src</earSourceDirectory>
          <modules>
            <webModule>
              <groupId>${project.groupId}</groupId>
              <artifactId>${base.name}</artifactId>
              <contextRoot>/workflow/${base.name}-${project.version}</contextRoot>
            </webModule>
          </modules>
        </configuration>
      </plugin>

 

Generate the adf-loc.jar
The adf-loc.jar file is an empty JAR file that is generated and placed in the EAR.  This contains a manifest classpath that adds the adf folder in the EAR to the classpath.  The below usage of the maven-jar-plugin generates the JAR file producing the same output as JDeveloper.
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.4</version>
        <executions>
          <execution>
            <id>adf-loc-jar</id>
            <phase>prepare-package</phase>
            <configuration>
              <finalName>adf-loc</finalName>
              <outputDirectory>${project.build.directory}/${project.build.finalName}/lib</outputDirectory>
              <excludes>
<exclude>**</exclude>
              </excludes>
              <archive>
                <manifestEntries>
                  <Class-Path>../adf</Class-Path>
                </manifestEntries>
              </archive>
            </configuration>
            <goals>
              <goal>jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
 
Modify the adf-config.xml
The last step is to modify the adf-config.xml.  When performing a diff on the EAR built by Maven and the one built by JDeveloper, I found that JDeveloper removes all metadata-namespaces and metadata-store-usages from this file when building the EAR.  The below section of the pom uses the xmltask Ant task to perform this modification.

 

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <id>adf-config-xml</id>
            <phase>prepare-package</phase>
            <configuration>
              <target>
                <path id=”ant-classpath”>
                  <fileset dir=”../build/lib”>
                    <include name=”*.jar” />
                  </fileset>
                </path>
                <taskdef name=”xmltask” classname=”com.oopsconsultancy.xmltask.ant.XmlTask” classpathref=”ant-classpath” />
                  <xmltask source=”${project.build.directory}/${project.build.finalName}/adf/META-INF/adf-config.xml”                                   dest=”${project.build.directory}/${project.build.finalName}/adf/META-INF/adf-config.xml” preserveType=”true”>
                  <remove path=”//*[local-name()=’metadata-namespaces’]/*” />
                  <remove path=”//*[local-name()=’metadata-namespaces’]/text()” />
                  <remove path=”//*[local-name()=’metadata-store-usages’]/*” />
                  <remove path=”//*[local-name()=’metadata-store-usages’]/text()” />
                </xmltask>
              </target>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

 

Summary
 
Using this pom file, you should be able to build an EAR file for your ADF application that is the same as the one generated by JDeveloper.  Again, you will still want to diff the results against what JDeveloper generates once in a while to make sure it is all still the same.  Some of these items may be specific to project settings or the version of JDeveloper being used.  Also note that because we are declaring a dependency on one or more WAR files, we need to be sure those WAR files are put in the repository before the EAR is build.  This can either be your local maven repository, which is done using the mvn install command, or a remote maven repository using the mvn deploy command.  Next, in part 4, we will cover adding an aggregator POM and configuring all of the projects to be built from Jenkins for continuous integration.