JaVa
   

Project Management with Maven

Now that we've seen all the pieces of Maven, where is a good place to start with your project? First, there are several questions you need to ask yourself:

  1. Does my project produce multiple artifacts?

    If your project produces a JAR file, an EAR file, and a WAR file, then the answer to this is yes. If it produces several JAR files that each do different things or contain different items, then the answer is yes. If you produce only a JAR file or a WAR file, then you are producing only one artifact for users.

  2. If the above answer is yes, then can you easily separate your project into discrete modules, like core/model, web, ear, etc.?
  3. What plug-ins will your project make use of?

    Will your project use Cactus, XDoclet, jcoverage, Hibernate? Make note of these and what versions of the plug-ins you wish to use.

  4. What reports do you want to generate for your project when you build your Web site?
  5. Do you want Cactus reports, jcoverage reports, Checkstyle reports? Make note of these to include in the reports section of your project descriptor.

Defining Your Project Structure

Once you have these questions answered you can now start with your first task: creating your project directory structure. I highly recommend following the standard structure that we discussed earlier. If you do decide to stick with your own, just make sure that you set all the appropriate elements in the project descriptor for the source directories and build directories. So a simple structure might look like this:

project.xml project.properties maven.xml src
 java
 test target (generated by Maven)


A more complex structure might look like this:

project.xml project.properties
maven.xml src
 java
 test core
 project.xml project.properties maven.xml
 src
 java
 test
 target (only for core)
web
 project.xml project.properties maven.xml
 src
 java
 webapp (for use with the war goal)
 target target (generated by Maven)


Defining Your Root Project Descriptor

The next step is to begin creating your main project descriptor (project.xml). As you were thinking about the items above, you may have formed an idea as to how you will structure your projects directory. If you are dealing with a multimodule project, you should create a subdirectory for each artifact under your main directory. For example, if you have a core module and a web module, you should create a directory for each of these under your root directory. Alternatively, you could keep your core code in the main directory (and not separate it out into its own directory) and put the Web code in a separate directory. I recommend starting with one of the sample POMs we have provided or building one from scratch. The file will need to be called project.xml and live in the root of the project tree. Once you have started you should decide on a group name and a project name. These respective names go in groupId and id elements. For a more descriptive name, use the name element. You will also need to choose a currently released version of the code; typically this will be something like 1.0-b1, 2.0, 3.1.1, or whatever your chosen versioning scheme is. If you haven't released anything yet, choose an appropriate number like .0.8.1-b45, which denotes that the project has not had a final release and is beta-quality software. Still in the top portion of the descriptor, we come to the organization element, which stores the information about what organization is the primary producer of this project. This element is used in the copyright and Web site creation. Along with this is the inception year of the project and the project's package, both of which are used in the JavaDoc creation. The next two items are the short description and description elements. If you want, you can leave them empty for the time being as they are only used in generating the Web site documentation. You should fill them in at some point, just to give your users more information about the project. In addition, there are other elements below these that are optional, such as url (the Web site's URL), issue tracking url (where bugs are filed), site address and directory (for uploading the built Web site), distribution site and directory (for artifact distribution), repository (the source code management repository descriptor string, typically CVS, but SVN will be available), versions (tagged versions that users can check out from SCM), and mailing lists (mailing lists, either external or internal, that users and developers can subscribe to). Now we come to the developers and contributors section. I recommend filling in the primary developers' information here. Primarily, this section is used for SCM and reporting, but it's always good to know who is working on the project and what role everyone plays in it. It is also nice to showcase contributors, so that they feel a sense of accomplishment from having contributed something back to the project. Following this is the licenses section, which allows you to specify what licenses this project is distributed under, be it Apache, GPL, LGPL, BSD-Style, or whatever. A copy of each license should also live in the root of the project directory and be referenced here. If you haven't chosen a license yet, I highly recommend doing so prior to releasing any code to steer clear of any ambiguity. If the project is a commercial one, then you will need to consult with your project leader or supervisor to determine what the license document needs to say. Several licenses are available for open-source projects (if yours is one); you can find these licenses at http://www.opensource.org/licenses/. These are strictly for the project itself and not for the dependencies, which we will get to shortly. Choosing an appropriate license may not be easy—you need to determine what your goals and needs are, so choose wisely. Now, we come to what can be one of the meatiest sections of any project descriptor: the dependencies. Pull out your list of JARs, EARs, or WARs that you wrote down earlier. These are dependencies that your project relies on, not what plug-ins you are utilizing rely on (those should be defined by the plug-in itself). First, determine whether or not a dependency is available on Ibiblio. To do so, visit the Maven repository on Ibiblio at http://ibiblio.org/maven. There you will see a directory listing of several projects; scan the list for the name of the project or a close approximation. If you don't see it initially, don't worry; next you look for the group name of the project (such as Avalon, which houses several subprojects). If you still can't find it, then you have three choices: download the JAR and place it on your own repository (this repository must mimic the layout that you see on Maven's repository); ask the Maven developers to upload the JAR to the repository (this is only an option if the JAR is freely available and its license allows it to be distributed elsewhere); or if the JAR is not freely available (such as many Sun- supplied JARs that require implicit license agreement), you can supply a URL for the dependency for end users to download and install into their own local repository. Once you have determined exactly what JARs, EARs, and WARs you need and where they are located, you still must determine what version you need. Unfortunately, making this decision is not the simplest task in the world. Several projects do not number their releases. The closest you can get at times will be a date of release. My best advice is to pick the closest number that you feel is right. It may take a few tries to get the right combination of JARs (some JARs rely on others with specific versions as well). Another option is to look at other projects, also using Maven, that rely on the same JARs you do and copy their dependencies. Now that we have our dependencies defined, we must define the rest of our project structure, specifically the source directory locations and what files we are going to include. The two primary elements we need to define are sourceDirectory and unitTestSourceDirectory. Then we should define what a test class looks like with respect to file naming. This step is identical to what you would do in an Ant build file when telling JUnit what to run. In addition, you can also define other resources that are necessary during unit testing; these can include property and configuration files, test data files, or other items you might need. After we have defined all of the unit test specifics, we can now define specific resources that the app needs in order to run. They can be identical to the resources that you just defined for unit testing or they can be completely different—it's all up to you.

There are also several other elements in here that may or may not be required, depending on your project: the nag e-mail address (when a build fails, Maven can be configured to automatically send an e-mail to this address), the aspect source directory (for AspectJ aspects that will need to be woven into your code just after building the code), source modifications (which define when and if a source should be included or excluded, depending on the class being loaded, and finally the reports element. If you want specific reports to be run, you must define them. The default reports that will run automatically are JUnit tests, dependency, and source cross reference. You can run a test build to determine what the default reports are.

Your project.properties File

Depending on what plug-ins you have decided to use in your project, you may have some very different properties in this file. One that is common, if you are hosting your own repository or you need to download a JAR from someone else's repository, is maven.repo.remote. This is a comma-separated list of HTTP-accessible repositories. The first repository should almost always be http://ibiblio.org/maven, followed by any other repositories that should be checked. Maven will look for all of your dependencies on Ibiblio first, and if it cannot find them it will move on to the next repository in the list until it does find them. There are several properties that you can set, so I encourage you to review the current Maven documentation to see what each of them does prior to changing them.

Your maven.xml File

Initially, your maven.xml file may define only your project's default goal, typically java:compile or jar:jar. A simple maven.xml file is shown here:

<project default="java:compile"/>


This tells Maven that when you type maven on the command line you want it to compile your project. You can change this to any of the goals that you see when you type maven –g. So, if you always want your project to be jar'ed for distribution you would change this to jar:jar, and then Maven would compile your code, run your unit tests, and then jar your project in the target directory.

In addition, if you want to specify some actions be taken before jar'ing your project, you would do so using some of the Jelly tags that we spoke of earlier. Primarily you want to focus on the preGoal, postGoal, and attainGoal tag elements.

Maven multiproject (reactor) and Subprojects

One of the core plug-ins that comes with Maven is the multiproject, or reactor, plug-in. This plug-in allows you to create a modularized project. Originally it was called reactor, but the name has recently been changed to multiproject; however, you will still find some documentation referring to it as the reactor plug-in. The plug-in, when called, analyzes all of the subprojects and determines which ones need to be built first. Whenever you extend a project file, you are implicitly using the multiproject plug-in each time you build that subproject.

Calling Subprojects from the Main Project Using reactor

For each subdirectory that you have created you will need to add the following to its project.properties file, specifying what artifact type will be the default:

maven.multiproject.type={war, jar, ear, ejb}


That way, when you run from the root of the project directory it knows exactly what type of artifact you wish to deploy from each subproject. Some of the built-in goals that you can automatically run on each subproject are

Running other goals on your respective subprojects is a little more involved, but not much. To call a specific goal on each subproject you must use the multiproject:goal goal. For example, to run clean and java:compile on each subproject use this:

maven -Dgoal=clean,java:compile multiproject:goal


This runs the clean goal and then the java:compile goal. If you wanted to add more goals, just specify them before or after these, separated by commas.

Building the Web Site

Now we have come to the final step in our project: creating the documentation and Web site. Honestly it shouldn't be the last thing that you think of, but most often it is. Maven steps in to help you out with this as well. All the documentation that Maven generates is processed as XML files, so if you want to change the files from HTML to PDF just grab your local PDF plug-in (http://maven.apache.org/reference/plugins/pdf/). Maven can also handle documentation in other formats depending on the platform. Some of these are DocBook (all platforms: http://maven.apache.org/reference/plugins/docbook/), Word for Windows (Windows only: http://maven.apache.org/reference/plugins/word2html/), or Tasklist (all platforms: http://maven.apache.org/reference/plugins/tasklist/). Primarily, though, most of the documentation you write will be in the XDoc format (http://jakarta.apache.org/site/jakarta-site-tags.html). XDoc was defined as a way to easily categorize information for the Jakarta project site and then attracted more widespread use. Unfortunately, not all of its XML elements are clearly defined as there is no schema or DTD to constrain what is and is not a valid element. Only the program parsing the file knows what it will and will not accept. Before I digress much further, all of your .xdoc files belong in the xdocs directory, and from there Maven grabs the files and transforms them along with the rest of the Maven-generated content to produce your site. If you run the DocBook plug-in as well, then those files will be processed along with everything else. To generate your site, it is simply another goal in Maven:

maven site:generate


This goal will parse through your XDocs and generated JUnit reports, jcoverage reports, and whatever else happens to be lying around in the target directory waiting to be turned into documentation.


JaVa
   
Comments