Part I: Setting up maven and overall structure
This will be the first of 2 part series where I would like to show how to quickly setup a Java Enterprise Application. In this part you will setup the overall project structure, configure your libraries, build path and module dependencies. I use RAD/Eclipse with m2Eclipse plugin which you can find here for development but the configuration is independent of what IDE or text editor you choose to use. So let's get started.
Pre-requisites:
- Maven 2. I used maven version 2.0.9. For a higher version of maven, please refer to maven documentation.
- Eclipse/RAD. Although you can do this without an IDE, it will nonetheless be easier to configure in an IDE since this is an Enterprise Application.
- JDK 1.4 or higher. I prefer JDK 5 or higher.
Overall structure
The enterprise application that I am going to setup will have a JAR module for services and DAOs, a WAR module that will import the JAR module and an EAR module that will include the WAR module. If you wish to add more modules, you can choose similar structure. You could have only WAR and JAR modules in eclipse, but it is preferable to house them within an EAR. Also RAD requires you to have a deployable EAR. Our WAR module will be deployed. To make this a maven project will have also have a parent-pom (which is not a module) sit above all three modules above that will package them together.
Look at the structure below to see how the structure will look like:
Setting individual modules starting with parent-pom
When you look at the image above, you will see three files: pom.xml, .project, .classpath. All three are important to configure. The IDE will generate your .classpath and .project files but I will nevertheless go through all of them to ensure that you understand what the IDE is generating. Also you can the .settings folder. This folder is specifically related to parent-pom. This folder will contain additional project/IDE related configurations. But I will not go through this because I don't want to make this too long. Also, the configuration for individual modules will be similar to what you will do for parent-pom. If you understand how I am going to configure these three files, you will easily be able to configure the rest.
So let's begin with pom.xml. Pom files are read by maven in order to do the following:
- Package modules. In this parent pom, you will package all three modules. The package name will be their folder names. In the EAR's pom, you would add the WAR module and in the WAR the JAR module. The JAR module will not have any module dependency.
- Define versioning, application description, url, name and so on. This is self explanatory. However, you'd want version to be consistent across all modules.
- Dependencies. You will define all the artifacts and their version that you'd use in your application. In this parent pom, you'd define all artifacts that are common to more than one module. For e.g you'd define log4j here since you'd need logging in both the JAR and WAR module. Same can be said of JUnit and Spring core libraries.
- Developers and Contributors. Optional. List out the developers/contributors and their roles.
- Plugin Lists. This lets you define your goals for you build process. For example, you'd use cobertura to see what percentage of your source code is unit tested.
- Reporting List. Optional. If your need is to generate reports, you'd use this. Again, as I mentioned you'd want to get cobertura report, here's where you define cobertura-maven-plugin.
- Repositories. A repository is where you'd pull all the artifacts from. Some private repos need authentication, but most don't. While your default settings.xml of maven is a good place to define your repositories, this is also another place to do so.
Please look at the code below for more info:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
<!--
This is the 'parent' POM (Project Object Model) which will have the following
nodes inherited by any POM which declared the <parent/> node to point to this
POM. Please note: This is not the 'super POM' which is supplied by Maven itself.
The super POM has its values inherited by all POMs.
* dependencies
* developers and contributors
* plugin lists
* reports lists
* plugin executions with matching ids
* plugin configuration
@author yourName
@version 1.0
-->
<!--
The POM version.
-->
<modelVersion>4.0.0</modelVersion>
<!--
The organization that is creating the artifact. The standard naming convention
is usually the organizations domain name backwards like the package name in Java.
-->
<groupId>com.yourCompanyName.ApplicationName</groupId>
<!--
The artifact name. This will be used when generating the phsyical artifact name.
The result will be artifactId-version.type.
-->
<artifactId>parent-pom</artifactId>
<!--
The type of artifact that will be generated. In this case no real artifact is
generated by this POM, only the sub projects.
-->
<packaging>pom</packaging>
<!--
The version of the artifact to be generated.
-->
<version>0.0.1-SNAPSHOT</version>
<!--
The name of the project to be displayed on the website.
-->
<name>Your Application Name</name>
<!--
The description of the project to be displayed on the website.
-->
<description>
Description of your app
</description>
<!--
The url of the project to be displayed on the website.
-->
<url>http://www.WARModuleURL.com</url>
<!--
This project is an aggregation/multi-module which includes the following
projects. Please note: the value between the module node is the folder
name of the module and not the artifactId value.
-->
<modules>
<module>AppNameJAR</module>
<module>AppNameWAR</module>
<module>AppNameEAR</module>
</modules>
<!--
This segement list the inherited dependencies for each child POM.
-->
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
......
</dependencies>
<!--
The following node defines the developers that are working on the project,
their roles and contact information. This will be used when the site is
generated for the project. (mvn site).
* id - The id of the developer.
* name - The display name that will be used for the display name under 'Project Team' of the website.
* email - The e-mail address of the team member which will be displayed.
* roles - A list of roles the member fulfills.
* organization - The organization of the developer.
* timezone - The timezone of the developer.
-->
<developers>
<developer>
<id>12344</id>
<name>Your Name</name>
<email>yourEamil</email>
<organization>
ABC company INC
</organization>
<organizationUrl>http://www.ABC_Comapnycom</organizationUrl>
<roles>
<role>Technical Leader</role>
</roles>
<timezone>+5:45</timezone>
</developer>
</developers>
<!--
The following node defines the contributors that are working on the project,
their roles and contact information. This will be used when the site is
generated for the project. (mvn site).
* name - The display name that will be used for the display name under 'Project Team' of the website.
* email - The e-mail address of the team member which will be displayed.
* roles - A list of roles the member fulfills.
* organization - The organization of the developer.
* timezone - The timezone of the developer.
-->
<contributors>
<contributor>
<name>SomeName</name>
<email>SomeEmail</email>
<organization>
ABC company INC
</organization>
<organizationUrl>http://www.ABC_Comapnycom</organizationUrl>
<roles>
<role>Engineering Manager</role>
</roles>
<timezone>+5:45</timezone>
</contributor>
...
</contributors>
<!--
Each POM file is a configuration file for the build process. There are many plug-ins
for adding new steps in the build process and controlling which JDK is being used.
Below we customize the version of the JDK as well as some code inspection tools like:
1. Cobertura
-->
<build>
<plugins>
<!--
Configure the maven-compiler-plugin to use JDK 1.5
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<fork>true</fork>
</configuration>
</plugin>
<!--
Configure Cobertura to ignore monitoring the apache log4j
class.
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<instrumentation>
<ignores>
<ignore>org.apache.log4j.*</ignore>
</ignores>
</instrumentation>
</configuration>
<!--
The following controls under which goals should this
plug-in be executed.
-->
<executions>
<execution>
<goals>
<goal>clean</goal>
<goal>cobertura</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.0.1</version>
<configuration>
<findbugsXmlOutput>true</findbugsXmlOutput>
<includeTests>false</includeTests>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<!--
Maven can look at various repositories to locate dependencies that
need to be downloaded and placed into the local repository. In the
below configuration, we enable codehaus, apache, and opensymphony
repositories.
-->
<repositories>
<repository>
<id>snapshots-maven-codehaus</id>
<name>snapshots-maven-codehaus</name>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
<url>http://snapshots.maven.codehaus.org/maven2</url>
</repository>
<repository>
<id>Maven Snapshots</id>
<url>http://snapshots.maven.codehaus.org/maven2/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-s3</id>
<name>Spring Portfolio Maven MILESTONE Repository</name>
<url>
http://s3.amazonaws.com/maven.springframework.org/milestone
</url>
</repository>
...
</repositories>
<!--
For the reporting area of the website generated.
1. JavaDoc's
2. SureFire
3. Clover
4. Cobertura
5. JDepend
6. FindBugs
7. TagList
-->
<reporting>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<reportOutputDirectory>${site-deploy-location}</reportOutputDirectory>
<destDir>${project.name}</destDir>
<aggregate>true</aggregate>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>surefire-report-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-clover-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jdepend-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<threshold>Normal</threshold>
<effort>Default</effort>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>taglist-maven-plugin</artifactId>
<configuration>
<tags>
<tag>TODO</tag>
<tag>FIXME</tag>
<tag>@todo</tag>
<tag>@deprecated</tag>
</tags>
</configuration>
</plugin>
</plugins>
</reporting>
</project>
Now that this is taken care of let's look into .project and .classpath quickly. The .project basically specifies build Commands. We will use eclipse's javaBuilder and maven2Builder. Look below.
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>parent-pom</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>
.classpath is where you'd define where you want the built packages to reside, your maven repository location, what your source files are and the path to them are. Here's one from the WAR module.
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
<classpathentry exported="true" kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="con" path="org.eclipse.jst.server.core.container/com.ibm.ws.ast.st.runtime.runtimeTarget.v61/was.base.v61"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
At this stage you have setup the overall project structure, configured your libraries, build path and module dependencies. You are now ready to build individual modules starting with your JAR, then WAR and finally adding them to EAR. You basically add JAR to WAR and only add WAR to EAR. You don't want cycilc dependency. I will show this in part II.
[...] been following along, this is part 2 of two part series in setting up Maven Enterprise Application. Here is part I which shows you how to use maven to setup the overall project structure, configure build [...]
ReplyDelete