May 2007
« June 2007 | Main | February 2007 »Maven 2 and Portal: Article Addendum
Thursday, May 31, 2007
Here is another follow-up blog entry on integrating Maven 2 and WebLogic Portal as that article seems to have generated quite a bit of interest. In particular there were a couple of questions and comments that came up a few times that I would like to address.
APP-INF/lib and Maven
The first question was how to deal with APP-INF/lib when using Maven, as most of you know APP-INF/lib provides a place to store library JARS that are accessible to the entire enterprise application. Traditionally, developers would drop the libraries into this directory and then simply manage them as an SCM artifact. If the library needed to be updated, the old version would be deleted from the SCM and a new version would be uploaded.
However this does not really conform with Maven's best practices where you would normally declare your dependencies in pom.xml and have Maven deal with it rather then do it manually. Fortunately there is an easy and convenient way to do this Maven and it provides a couple of significant benefits as follows:
- You don't need to check these artifacts into the SCM, instead Maven will resolve the dependencies and updating to a later version of a library is simply a matter of updating pom.xml.
- Maven resolves all the dependencies for the libraries declared, this means that if a library you want to use in turn depends on another library, this secondary dependency will automatically be included. So in this saves times since you don't have to figure out the dependency chain for a library.
In order to set this up for your own project, follow these instructions.
Step 1 - Add the libraries as modules to the EAR pom.xml
The first step is to add your libraries as jar modules to the EAR's pom.xml, this can be done by simply adding new elements to the module section as follows:
<modules>
...
<jarModule>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</jarModule>
...
</modules>
Note that anything you add here must also be added to the dependencies section of the POM along with the version number of the dependency. As mentioned earlier, if the declared library has dependencies on other libraries these will also be brought into APP-INF/lib. This is a significant benefit however one drawback of this is that sometimes you get a library you don't need because it is provided by the container. For example, commons-logging has a dependency on the javax servlet-api library but this is provided by WebLogic and is not needed in APP-INF/lib. To avoid dragging this JAR in, declare the dependency as follows:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
Step 2 - Make APP-INF/lib the output directory for bundled libraries
The next step is to make APP-INF/lib the output folder for libraries when Maven builds the EAR rather then the root folder of the EAR. You can specify this in one of ways, either with each library or once by declaring APP-INF/lib as the default. I prefer the latter approach and this can be done by using the defaultLibBundleDir element in pom.xml as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
...
<defaultLibBundleDir>APP-INF/lib</defaultLibBundleDir>
...
</configuration>
</plugin>
Step 3 - Optionally enable copying dependencies to APP-INF/lib
Depending on how your development environment is configured, you may need to provide a mechanism for developers to physically copy the libraries to APP-INF/lib so that they can perform their development tasks. For example, if you are not using the Maven Eclipse plugin, these libraries need to be physically on the classpath in order for Workshop to pick them up.
To accomplish this goal, we will use the Maven 2 dependency plugin. It provides a goal called copy-dependencies that will accomplish what we need with a bit of configuration. To do this, first add a plugin to the build section of the EAR's pom.xml as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<excludeScope>provided</excludeScope>
<includeTypes>jar</includeTypes>
<excludeTypes>war</excludeTypes>
<overWrite>true</overWrite>
<outputDirectory>/EarContent/APP-INF/lib</outputDirectory>
</configuration>
</plugin>
With this added a developer can then type mvn dependency:copy-dependencies to have all of the EAR dependencies copied into APP-INF/lib. We can also optionally add some functionality to the clean goal so that these libraries are removed from APP-INF/lib when mvn clean is invoked. To do this, we again add a plugin to the build section of the EAR's pom.xml as follows:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>${basedir}/EarContent/APP-INF/lib</directory>
<includes>
<include>**/*.jar</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
Finally, one potential issue is that most EAR projects that use Maven are organized with a parent project with an EAR, WAR and other projects organized as children of that parent. If the developer accidentally types mvn dependency:copy-dependencies at the parent project level a lot of dependencies in other projects, such as the WAR, will be copied to default locations needlessly. To prevent this, we can add an element to the parent project's pom.xml that stops this goal from doing anything by default. I find adding the following plugin declaration to the parent's pom.xml build section works well for me:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<excludeTypes>jar,war,ear,pom</excludeTypes>
<overWrite>false</overWrite>
</configuration>
</plugin>
Maven and Workshop Integration
Another question that arose frequently was how to integrate Maven with Workshop. When using Maven with Eclipse, there are two approaches that can be used as follows:
- Use the Maven Eclipse Plugin that manages pom.xml and creates a Maven classpath container with all of the dependencies in pom.xml.
-
Use the
mvn eclipse:eclipsecommand to generate an Eclipse project from a pom.xml
I have only tried the first approach, the second approach may work but I have not tested it. I was concerned that the second approach may not be feasible with shared libraries, something we wanted to leverage but admittely I haven't spent a lot of time looking into this. With regards to the first approach, the Maven Eclipse plugin has worked relatively well for me concerning it is still early days however I have only been able to get the 0.0.9 version to work, the current 0.0.10 version doesn't seem to play nicely with Workshop.
Maven WebLogic Shared Library Plugin
As part of the article I wrote, I developed a Maven plugin that would import a shared library into the Maven repository. There were a couple of bug reports from that including that it would not handle a SNAPSHOT version or group names that were nested with the dot notation. Both of these issues have been corrected and I have attached the latest source to this article, it can be retrieved here maven-weblogic-library-plugin.zip.
I also made a minor change in the way the plugin works, there are now two separate goals, one that installs a single library and one that installs a directory of libraries. If you use this updated version make sure to update your scripts accordingly.
Finally, if you are building your own shared libraries, I would recommend using the mvn install command to install them instead of this plugin. This plugin is designed to handle third party libraries and generates custom POMs for the libraries, by using mvn install your libraries are installed with the POMs you developed.
Maven APT Plugin
The Maven APT Plugin has been corrected to address the initial issues I had with it, I would highly recommend using the public version versus the patched version I included with the article.
Posted by Gerald Nunn at 4:01 PM | Categories: WebLogic | Permalink |
Maven 2 and Checkstyle
Wednesday, May 23, 2007
I recently wrote an article about integrating Maven 2 with WebLogic Portal and I found working with Maven an interesting experience. One excellent feature of Maven 2 that I am extensively using is the ability to generate a web site for the project automatically. This web site can include a variety of generated reports including project information and documentation, the results of your unit tests, javadoc and more.
One of the available reports in Maven is a Checkstyle report, I wanted to leverage it in order to ensure compliance with the organization's coding standards. If you are not familiar with Checkstyle, it parses your source code and provides a report with regards to how compliant the code is with a given convention. Additional information on Checkstyle can be found at http://checkstyle.sourceforge.net.
Checkstyle ships with a few default conventions including the Sun coding standards, however most organizations customize this and create their own configuration. The question arises though as to how to centralize this configuration so that it does not need to be manually configured when a project build is done.
Fortunately, this issue is easily addressed using the built-in dependency mechanism in Maven. Essentially we simply bundle the Checkstyle xml configuration file into a JAR and then install this into a Maven repository, typically this will be an organization's internal intranet repository. When the project site is built, this configuration is automatically fetched from the repository and applied when needed.
Configuring this is straightforward, first in the project pom.xml we define the dependency on the checkstyle configuration JAR as an extension dependency, this can be done as follows:
<build>
<extensions>
<extension>
<groupId>com.bea.ps</groupId>
<artifactId>checkstyle-config</artifactId>
<version>1.0.0</version>
</extension>
</extensions>
</build>
Next we reference the configuration file in the Checkstyle plug-in configuration in the reporting section. Note that the Checkstyle plugin will search the URL classpath for the resource before trying the file system, this is why storing the configuration file in a JAR works. The configLocation referenced below is where checks.xml is located on the classpath in the checkstyle-config.jar referenced above.
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<configLocation>config/checks.xml</configLocation>
</configuration>
</plugin>
</plugins>
</reporting>
That should be it, now the configuration can be centrally managed and controlled and projects can get the latest version simply by updating the version of the artifact in the extension section.
Posted by Gerald Nunn at 4:02 PM | Categories: Java | Permalink |
