October 4 2012

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 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/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.

 

About the Author

Adam Desjardin

Adam DesJardin is the Chief Technology Officer for AVIO Consulting.  Adam focuses on technical strategy, standards and delivery both within AVIO and for our customers.  Prior to joining AVIO in 2007, Adam held various consulting and architecture positions at Fuego and BEA Systems where he developed and delivered process and service driven solutions.

Join the Conversation

January 23, 2014

Hi Adam,

Congratulations for your excelent blog, it's really interesting and now it's being more and more useful for me.

I want ask you about part 4 of this entry. I'm interested on how implement the end-to-end example.

I have followed all parts but now I'm facing some issues with ear generation. I believe it's related with my poms configuration.

Thansk a lot!

Cheers

February 27, 2014

Learned a lot from this blog post, thanks Adam

December 10, 2015

Great

Enter your first name. It will only be used to display with your comment.
Enter your email. This will be used to validate you as a real user but will NOT be displayed with the comment.
By submitting this form, you accept the Mollom privacy policy.