Saturday, May 13, 2006

How to make JavaEE project with Maven2

You want to support multiple modules in your project. Suppose you plan to have these modules:

- Java Module (one or more);
- EJB Module (dependent on Java Module);
- WEB Application Module (dependent on Java and EJB Modules);
- Enterprise Application Module (dependent on Java, EJB and Web Application Module).

First of all, you have to create multi-module project. It is special type of maven project - it does not produce any artifact. Its main purpose is to host modules - single maven projects - and to perform group operations for all modules.

Each single maven project should be aware of parent project. The same is true for parent maven project - it has to be aware about all the children.

The following steps describe whole process of creating such a project.

1. Create multi-project with the following directory structure:

myMultiProject
    myJavaModule1
    myJavaModule2
    ...

    myEJBModule1
    myEJBModule2
    ...

    myWebApplicationModule1
    myWebApplicationModule2
    ...

    myEnterpriseApplicationModule


2. Create maven project "pom.xml" files inside parent directory and inside each child project. Each "pom.xml" file contains specific to given project information.

myMultiProject
    myJavaModule1
        pom.xml
    myJavaModule2
        pom.xml
    ...

    myEJBModule1
        pom.xml
    myEJBModule2
        pom.xml
    ...

    myWebApplicationModule1
        pom.xml
    myWebApplicationModule2
        pom.xml
    ...

    myEnterpriseApplicationModule
        pom.xml

    pom.xml


You can auto-generate "pom.xml" files by using special "archetype:create" command. Only these archetypes are supported now: "quickstart", "webapp", "site", "mojo" and "marmalade-mojo". For our process we can use only 2 first archetypes.

Run these commands:

- for parent multi-project (in the directory where you plan to hst whole project):

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId -DartifactId=myMultiProjectArtifactId -DpackageName= -Dversion=1.0

This command creates the directory with the name specified as artifactId: "myMultiProjectArtifactId". You have to change "packaging" value from "jar" to "pom" inside "pom.xml".

You have to change current directory to "myMultiProjectArtifactId" before running all following commands.

- for Java Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myJavaModule1 -DpackageName=my.new.package -Dversion=1.0

This command creates "myJavaModule1" with minimal set of directories/files for "quickstart" archetype.

- for EJB Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myEJBModule1 -DpackageName=my.new.package -Dversion=1.0

This command creates "myJavaModule" with minimal set of directories/files for "quickstart" archetype.

- for Web Application Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myWebApplicationModule1 -DpackageName=my.new.package -Dversion=1.0

This command creates "myWebApplicationModule1" with minimal set of directories/files for "webapp" archetype.

- for Enterprise Application Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myEnterpriseApplicationModule -DpackageName=my.new.package -Dversion=1.0

This command creates "myEnterpriseApplicationModule" with minimal set of directories/files for "quickstart" archetype.

As you can see, for Java, EJB, Enterprise Application Modules and Multi-Project we use "quickstart" archetype and for Web Application - "webapp" archetype.

The cyclic dependency between parent and children projects should be expressed in the following way: for parent project we have to use "modules" tag, for children projects - "parent" tag.

Parent project's structure looks like this:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Specify group ID, artifact ID and version for the parent project. -->
  <groupId>myMultiProjectGroupId</groupId>
  <artifactId>myMultiProjectArtifactId</artifactId>
  <version>myMultiProjectVersion</version>

  <!-- 2. Specify "pom" type. This type indicates that this project is parent multi-project. -->
  <packaging>pom</packaging>

  <!-- 3. List all children projects names (name is directory name as well). -->
  <modules>
    <module>myJavaModule1</module>
    <module>myJavaModule2</module>
    ...
    <module>myEJBModule1</module>
    <module>myEJBModule2</module>
    ...
    <module>myWebApplicationModule1</module>
    <module>myWebApplicationModule2</module>
    ...
    <module>myEnterpriseApplicationModule</module>
  </modules>

</project>


Child project's structure looks like this:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Specify group ID, artifact ID and version for child project. -->
  <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
  <artifactId>myJavaArtifactId</artifactId>
  <version>myJavaModuleVersion</version>

  <!-- 2. Specify the type of the project:
           "jar", "war", "ear". "ejb", "ejb3", "rar", "par", "pom", "maven-plugin" -->

  <packaging>jar</packaging>

  <!-- 3. Specify parameters and the location of the parent project. -->
  <parent>
    <groupId>myMultiProjectGroupId</groupId>
    <artifactId>myMultiProjectArtifactId</artifactId>
    <version>myMultiProjectVersion</version>
    <relativePath>../pom.xml</relativePath>
  </parent>
</project>



3. Java Module


Below is typical "pom.xml" content for Java Module:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>jar</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another libraries, projects etc. -->
  <dependencies>
    ...
  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myJavaModule1FinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. Specify the location of sources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/java -->
    <sourceDirectory>../src/java</sourceDirectory>

    <!-- 4.3. Specify the location of the filter file (if filtering is used). -->
    <filters>
      <filter>target/filter.properties</filter>
    </filters>

    <!-- 4.4. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/resources -->
    <resources>
      <resource>
        <directory>../src/resources</directory>
        <filtering>true</filtering>
        <excludes>
          <exclude>*web*.xml</exclude>
        </excludes>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>

          <!-- 4.5. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>

          <!-- 4.6. Specify files to include. -->
          <includes>
            <include>**/com/**</include>
          </includes>

          <!-- 4.7. Specify files to exclude (if required). -->
          <excludes>
            <exclude>com/sun/**/*.java</exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>


4. EJB Module

EJB Nodule is dependent on Java Module:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>ejb</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another libraries, projects etc. -->
  <dependencies>
    <!-- 3.1. Specify dependencies on external libraries. -->
    ...

    <!-- 3.2. Specify dependencies on EJB libraries. -->
    <dependency>
      <groupId>javax.ejb</groupId>
      <artifactId>ejb</artifactId>
      <version>2.1</version>

      <!-- 3.2.1. This library is provided by EJB Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.3. Specify dependencies on internal libraries. -->
    <dependency>
      <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
      <artifactId>myJavaModule1ArtifactId</artifactId>
      <artifactId>myJavaModuleVersion</artifactId>

      <!-- 3.3.1. This library is required at runtime. -->
      <scope>runtime</scope>
    </dependency>
  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myEJBModule1FinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. Specify the location of sources (if you have non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/java -->
    <sourceDirectory>../../src/java</sourceDirectory>

    <!-- 4.3. We don't want to filter for this module: "filters" section is empty. -->

    <!-- 4.4. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/resources -->
    <resources>
      <resource>
        <directory>../src/java/META-INF</directory>
        <targetPath>META-INF</targetPath>
        <filtering>false</filtering>
        <excludes>
          <exclude>*application*.xml</exclude>
        </excludes>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <!-- 4.5. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>

          <!-- 4.6. Specify files to include. -->
          <includes>
            <include>**/ejb/**</include>
          </includes>

          <!-- 4.7. Nothing to exclude. -->
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>



5. WEB Application Module

Web Application Module is dependent on Java and EJB Modules.

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>war</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another libraries, projects etc. -->
  <dependencies>
    <!-- 3.1. Specify dependencies on external libraries. -->
    ...

    <!-- 3.2. Specify dependency on servlet API library. -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.4</version>

      <!-- 3.2.1. This library is provided by Web Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.3. Specify dependency on JSP API library (if required). -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>

      <!-- 3.3.1. This library is provided by WEB Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.4. Specify dependency on other web libraries: tags, struts, tiles etc... (if required). -->
    ...

    <!-- 3.5. Specify dependency on database driver (if required). -->
    <dependency>
      <groupId>oracle</groupId>
      <artifactId>oracle-driver</artifactId>
      <version>9.2.0.5.0</version>
    </dependency>

    <!-- 3.6. Specify dependencies on EJB libraries (if required). -->
    <dependency>
      <groupId>javax.ejb</groupId>
      <artifactId>ejb</artifactId>
      <version>2.1</version>

      <!-- 3.6.1. This library is provided by EJB Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.7. Specify dependencies on internal libraries. -->
    <dependency>
      <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
      <artifactId>myJavaModule1ArtifactId</artifactId>
      <artifactId>myJavaModule1Version</artifactId>

      <!-- 3.7.1. This library is required at runtime. -->
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
      <artifactId>myEJBModule1ArtifactId</artifactId>
      <artifactId>myEJBModule1Version</artifactId>

      <!-- 3.7.2. This library is required at runtime. -->
      <scope>runtime</scope>
    </dependency>

  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myWebApplicationModule1FinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. Specify the location of sources (if you have non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/java -->
    <sourceDirectory>../src/java</sourceDirectory>

    <!-- 4.3. We don't want to filter for this module: "filters" section is empty. -->

    <!-- 4.4. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/resources -->
    <resources>
      <resource>
        <directory>../src/config</directory>
        <filtering>false</filtering>
        <includes>
          <include>*.properties</include>
        </includes>
      </resource>

      <resource>
        <directory>../src/resources</directory>
        <filtering>false</filtering>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <!-- 4.5. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>

          <!-- 4.6. Specify files to include. -->
          <includes>
            ...
          </includes>

          <!-- 4.7. Specify files to exclude (if required). -->
          <excludes>
            ...
          </excludes>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <!-- 4.8. Specify the location of Web Application directory (if non-standard). -->
          <!-- Defailt is: ${basedir}/src/main/webapp -->
          <warSourceDirectory>../src/web</warSourceDirectory>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>


6. Enterprise Application Module

This module performs main assembly work plus adds some application-level resources, like "application.xml" file. You have to list all the modules to be included into "ear" file in "dependencies" section. Each module should be marked with the corresponding type: "jar", "war", "ejb", "ejb3", "ejb-client", "rar", "par", "sar".

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>ear</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another modules within the multi-module project. -->
  <dependencies>
    <dependency>
      <!-- 3.1. Dependency on Java Module. -->
      ...
      <type>jar</type>

      <!-- 3.2. We need to include this module into application.xml; required by EJB module. -->
      <includeInApplicationXml>true</includeInApplicationXml>
    </dependency>

    <dependency>
      <!-- 3.3. Dependency on EJB Module. -->
      ...
      <type>ejb</type>
    </dependency>

    <dependency>
      <!-- 3.4. Dependency on Web Application Module. -->
      <type>war</type>
    </dependency>
  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myEnterpriseApplicationModuleFinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. We don't want to filter for this module: "filters" section is empty. -->

    <!-- 4.3. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${project.build.outputDirectory} -->
    <!-- The file: application.xml will be automatically generated. -->
    <resources>
      <resource>
        <directory>../src/java/META-INF</directory>
        <targetPath>META-INF</targetPath>
        <filtering>false</filtering>
        <includes>
          <include>weblogic-application.xml</include>
        </includes>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>

        <!-- 4.4. Specify used Java version. -->
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-ear-plugin</artifactId>
        <configuration>

          <!-- 4.5. Specify modules to include. -->
          <modules>

            <!-- 4.5.1. Include Java Module. -->
            <javaModule>
              <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
              <artifactId>myJavaModule1ArtifactId</artifactId>
              <artifactId>myJavaModule1Version</artifactId>

              <!-- 4.5.1.1. Only if you want different file name inside "ear" file. -->
              <bundleFileName>myBundleJavaModule1FileName</bundleFileName>
            </javaModule>

            <!-- 4.5.2. Include EJB Module. -->
            <ejbModule>
              <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
              <artifactId>myEJBModule1ArtifactId</artifactId>
              <artifactId>myEJBModule1Version</artifactId>

              <!-- 4.5.2.1. Only if you want different file name inside "ear" file. -->
              <bundleFileName>myBundleEJBModule1FileName</bundleFileName>
            </ejbModule>

            <!-- 4.5.3. Include Web Application Module. -->
            <webModule>
              <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
              <artifactId>myWebApplicationModule1ArtifactId</artifactId>
              <artifactId>myWebApplicationModule1Version</artifactId>

              <!-- 4.5.3.1. Only if you want different file name inside "ear" file. -->
              <bundleFileName>myBundleWebApplicationModule1FileName</bundleFileName>

              <!-- 4.5.3.2. Specify the context root if you need different name. -->
              <!-- Default is: "/${pom.artifactId} -->
              <contextRoot>iris</contextRoot>
            </webModule>

            <!-- 4.5.4. Maven will also treat dependent 3-rd-party libraries as modules.
                        You have to exclude them or redirect to "APP-INF/lib" directory. -->
            <javaModule>
              <groupId>antlr</groupId>
              <artifactId>antlr</artifactId>
              <bundleDir>APP-INF/lib</bundleDir>
            </javaModule>
            ...

          </modules>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>



7. Parent multi-project

Parent project can be used as convenient way to execute group commands, When you run particular command on the project, it executes this command for all children projects. Maven is able to discover the correct execution order and to detect circular dependencies.

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Parent multi-project description. -->
   ...
  <packaging>pom</packaging>

  <!-- 2. Chlidren modules description. -->
  <modules>
    ...
  </modules>

  <build>
    <defaultGoal>package</defaultGoal>
   
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <!-- 3. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>



8. Usage

Now you can execute group commands, for example:

>mvn compile
>mvn install
>mvn site


These commands perform operations for each module sequentially.

167 comments: