Sunday, March 6, 2011

Configure Eclipse Projects from Maven with AntRun and XMLTask

Imagine a perfect world of tool usage: Every developer would use the same tools and identical tool configuration. To achieve this smoothly, every setup step should be automated. But when a team uses m2eclipse, the project configuration is not under version control. Instead, files like .project, .classpath and the .settings directory are generated upon checkout. m2eclipse uses definitions from pom.xml to derive the Eclipse configuration. I will introduce an approach how an organization can modify and extend this automatic configuration for its needs. This is the final chapter of a three post series. Last times, I presented how seamless integration of Maven and Eclipse significantly contributes to code quality and why project configurators do not yet accomplish this perfectly.[1],[2]

The overall approach
We rely on custom file adapters for Maven to access the configuration files of Eclipse. These adapters could be written in any language. Because Ant is well integrated into Maven and still common, I chose the Maven AntRun Plugin. It is accompanied by XMLTask[3] for efficiently creating and modifying the necessary XML files via XPath. Be sure to use version 1.16.1 to avoid the UnsupportedClassVersionError.[4]

Eclipse configuration with AntRun and XMLTask
Figure 1: Eclipse configuration with AntRun and XMLTask (click to enlarge)

Again, let's take the PMD Eclipse Plugin as example. To leverage the PMD configuration in pom.xml for Eclipse, the adapter acts as follows:
  1. On checking out or editing pom.xml, m2eclipse creates or updates the configuration of the java project.
  2. Our Ant script reads the files provided by m2eclipse. Based on properties in pom.xml, it modifies these files:
    • It adds the PMD project facet and the PMD builder to .project.
    • It creates the files .pmd and project-ruleset.xml.
Figure 1 shows the complete interaction of the components and files. For the relationship with the Maven repository see the first post.[1]

An example adapter in detail
We use the Maven AntRun Plugin to call our adapter. The adapter is an Ant target defined in build.xml and called modify-eclipse-pmd. In the property pmd.ruleset.filename it receives the name of the local instance of the central PMD ruleset:

In our build.xml we define the necessary properties and the xmltask task:

For convenient handling of natures and builders in the .project file, we provide the Ant macros checknature and addnatureandbuilder:

The target modify-eclipse-pmd checks .project for the PMD nature. If this nature is not existing in the file, the target modify-eclipse-pmd-insertion is called. Additionally, modify-eclipse-pmd creates the configuration file .pmd and the ruleset file project-ruleset.xml. These files are recreated on each execution to reflect changes of the underlying properties. For stable build configurations, these tasks could be moved to modify-eclipse-pmd-insertion to be executed only once.

The target modify-eclipse-pmd-insertion adds the PMD nature and the PMD builder to .project:

Ruleset handling
The PMD ruleset can be a classpath resource or a file. I opted for the file approach due to problems with modified JARs.[2]

The path to the central ruleset file is resolved as follows: .pmd → project-ruleset.xml → target/pmd-ruleset.xml. The intermediate file project-ruleset.xml is necessary because .pmd cannot reference relative paths. The central ruleset target/pmd-ruleset.xml is available as soon as PMD is executed once via Maven.

Open for further usage
If you plan to write your own adapters, I recommend the following steps:
  1. Make a copy of your Eclipse project for later comparison.
  2. Manually configure your Eclipse project for the things that shall be done in the future be the adapter. For example, activate FindBugs under Project→Properties→FindBugs and augment the analysis effort to “Maximal”.
  3. Diff the modified version of your Eclipse project with the original version from step 1 on a file basis. Note any modified file, in our FindBugs example the newly created files .fbprefs and .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs as well as the modified file .project.
  4. Copy the adapter example given here as skeleton.
  5. Modify the adapter skeleton to achieve exactly the modifications from step 3.
  6. Test your adapter with a fresh project.
  7. Integrate the call of your adapter into the company parent POM to propagate it to all developers.
  8. Inform the developers about the changes and the motivation behind.
This way, you should be able to achieve any configuration you need all over your team.

Extensions as desired
The basic solution above can be refined in several ways:
  • The file target/pmd-ruleset.xml could be excluded in the clean goal. After execution of clean, this modification would allow for calling PMD in Eclipse without re-running PMD once via Maven.
  • For multiple projects, the duplicate code from their build.xml files should be refactored into one central build-common.xml. Each individual build.xml can import build-common.xml then. The Maven Dependency Plugin will provide build-common.xml from the Maven repository.
  • Some packages could be excluded from the PMD analysis, e.g. when using third-party sources. I have written a second ant target that uses XMLTask to add the exclusions to project-ruleset.xml. It's a bit tricky because project-ruleset.xml uses the namespace "http://pmd.sf.net/ruleset/1.0.0" and it uses it as default namespace with empty prefix as namespace binding. Additionally, XMLTask treats the XML structure to be inserted as separate and independent document. Therefore, I had to use XPath expressions like "/:ruleset/:description" and XML-Elements with explicit namespace, for example "<exclude-pattern xmlns="http://pmd.sf.net/ruleset/1.0.0">.*/${source.exclusion.path.relative}/.*</exclude-pattern>".
All these extensions can be done with minimum effort and do underlie the general advantages described in the next section.

Advantages: transparency and universality
Eclipse project configuration with small adapters and XMLTask has two main advantages:
  1. It is completely transparent and under control. These white boxes meet exactly your requirements. For example:
    • Chose if PMD and Checkstyle should use classpath resources or local files for their configuration
    • Specify a separate header file for Checkstyle
    • Define excludes
  2. It is universal. Everything setting in structured text files can be reached. For example:
    • Use it for workarounds for bugs in Eclipse/m2eclipse[5]-[7]
    • Configure any Eclipse plugin for software quality measurement, e.g. FindBugs[8], Classycle[9] or Macker[10]
    • Configure other Eclipse plugins with properties from pom.xml, for example set a custom WAR directory for the Google Eclipse Plugin (GEP)[11]
The pros look impressive, but we should reflect the flip side of the coin.

Minor downsides to be accepted
There are some drawbacks of the adapter approach. In my experience, they only have minor impact:
  • They rely on text file formats. This is not the official API for configuring Eclipse. But over the years, these formats have proven to be self explaining and stable.
  • Somebody has to develop, test and maintain the adapters. However, once accommodated with the technique, it takes less than an hour to develop an additional adapter.
  • Information from pom.xml can be obtained only from properties. POM inheritance and plain text configuration cannot be used. I could overcome this by factoring out all relevant settings to Maven custom properties. For example, checkstyle.header.file is defined for the header file location. This property is used twice: in the configuration of the Maven Checkstyle Plugin and for AntRun to be passed to Ant. Proper usage of such properties has to be taken care of during enhancements. This can be ensured if all build components are only maintained by a few experts.
  • To recognize some of the file modifications, Eclipse has to be restarted. This is the biggest flaw. Without restart after initial checkout, the additional builders are not executed. A warning message on checkout could remind the users. Fortunately, Eclipse picked up all other modifications on the fly or on refresh with F5.
  • The adapters only run according to the executions we define for the AntRun plugin. I use the prepare-package phase as execution. This is a trade-off between build time and up-to-dateness. An execution in the validate or initialize phase felt too time-consuming for me without solid-state disk.
Trading-off the pros and cons, the file adapter approach proved advantageous for me.

An out of the box solution at the horizon?
Hopefully one day, Eclipse, m2eclipse, Maven and the analysis plugins will integrate seamlessly. Each relevant Eclipse Plugin would offer a feature complete project configurator for m2eclipse. At least, the plugin developers tighten the integration release by release. For example, m2eclipse will introduce the support for suppression flags to overcome the redundant execution of the analysis plugins under Eclipse.[12]

References
  1. ^ Ackermann, M. Solutions for Enterprise IT. "Use Maven to Configure Checkstyle, PMD and FindBugs Consistently in Eclipse" [cited 2011 Feb 27]
  2. ^ Ackermann, M. Solutions for Enterprise IT. "m2e-extensions or m2e-code-quality as Project Configurators for Checkstyle, PMD and FindBugs" [cited 2011 Feb 27]
  3. ^ OOPS Consultancy Ltd. OOPS Consultancy Homepage. "XMLTask" [cited 2011 Feb 27]
  4. ^ Stack Overflow Internet Services, Inc. Stack Overflow. "XMLTask 1.16: Does it work with Ant so far?" [cited 2011 Mar 6]
  5. ^ Sonatype, Inc. Sonatype Forge. "Resources are always excluded" [cited 2011 Mar 6]   
  6. ^ Sonatype, Inc. Sonatype Forge. "Allow filtering of web.xml" [cited 2011 Mar 6]  
  7. ^ Sonatype, Inc. Sonatype Forge. "Web resources filtering with m2eclipse" [cited 2011 Mar 6]  
  8. ^ Hovemeyer D. H., Pugh W. W. FindBugs™ Manual. "Chapter 7. Using the FindBugs™ Eclipse plugin" [cited 2011 Mar 6]
  9. ^ graf technologies GmbH. graf technologies Home. "Classycle Plugin for Eclipse" [cited 2011 Mar 6]
  10. ^ Geeknet, Inc. SourceForge. "Eclipse Macker" [cited 2011 Mar 6]
  11. ^ Google, Inc. Google Web Toolkit (GWT) Issues. "GEP: cannot set a custom WAR directory" [cited 2011 Mar 6]
  12. ^ Tatavu, V. m2e-users Mailing List. "A design dilemma for supporting parallel maven/eclipse plugins"[cited 2011 Mar 6]

No comments:

Post a Comment