Recently, and while looking at some quite complex Maven POMs it just occurred to me that allot of the information we get to see inside of a POM file is simply not required to be there during the development process. This happens because Maven is designed to cover the full development life-cycle, meaning that it will also include the necessary configuration for a multitude of build scenarios. For example, it might contain different profiles for internationalization, clustering and much more. So, can we make it simpler, more standardized and easier to read and understand? I happen to think so.
No soup for you!
Quite often we see build related information mixed in what I would call a soup of different properties used inside of an even messier pool of profiles. In such scenarios it is quite easy for the developer to start losing focus and therefore time in order to be able to track the different properties and where and how they are used within large POMs.
For the most part of their development cycle, developers are simply interested in the project dependencies, unit and integration testing and basic packaging and deployment. As a project grows it becomes necessary to add different profiles that require specific settings in order to adapt to the different build scenarios. In short, the POMs will slowly become this large agglomerate of different and messy configuration contexts.
Context is king
Our brain absorbs and organizes information much faster if the contexts are clear. Clear contexts make any learning or information dissemination process much easier to digest. We do it all the time and, unlike me, good writers can pass their view points in a much easier and concise way.
POM files can easily grow to include quite a large amount of information in them as shown in the image bellow.
A typical POM directory structure for an enterprise level web application can be something like this:
Root pom.xml |-> EAR pom.xml |-> EJB pom.xml |-> WAR pom.xml
In addition to the above setup developers also tend to define a standard structure for the POM xml. This is normally done in the name of clarity and contextualization within the POM but because POMs do not enforce that structure automatically, then it is just a question of time until the POM becomes messy.
Another good practice is to place the dependencies, properties and profiles common to all projects at the ROOT level. Unfortunately, the same is not true for the specific counterparts that are placed at the end-nodes.
A possible approach
The approach that I’m presenting basically tries to present a possible solution to further slim down the complexity verified at the end-nodes. I’m hoping to achieve this by cutting down on POM sugar and properties carbs:
- Move the definition and maintenance of properties out of the pom and into properties files or into a Properties Management System.
- Move specific build configuration out of the main nodes and into build specific projects.
Codehaus provides a Properties Maven Plugin that aids on the loading of properties files into the POM environment.
This is pretty much standard practice in Maven land and many of you know about this for a long time. What you might not know is that the next version of this plugin (alpha-3) will support properties loaded from a URL! Yes, this means is that we can now move the properties out of the configuration projects and store them in a Properties Management System web application.
Checkout the latest release from their subversion repository and build it locally so that you get the required POM in your local maven repo.
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>properties-maven-plugin</artifactId> <version>1.0-alpha-3-SNAPSHOT</version> <executions> <execution> <phase>validate</phase> <goals> <goal>read-project-properties</goal> </goals> <configuration> <urls> <url>http://traits-cfp.rhcloud.com/traits/rest/properties/download/i8n/common/welcomePT</url> </urls> </configuration> </execution> </executions> </plugin>
Notice that the URL points to a server on the Red Hat cloud. That’s Traits, a simple and utterly ugly prototype that I’ve developed of what a Properties Management System could start to look like. A better approach would be to have it integrated in Maven CMS systems like Artifactory, Nexus or Arquiva.
At a minimum, the Property Management System should allows users to:
– Provide an API from where to download the configured properties sets or subsets
– Easily manage different sets of properties
– Organize the order of delivery on full set request
– Request properties based on Maven like versioning, maybe as query parameter in the REST API (not implemented in demo)
– Execute variable substitutions on given sets or subsets (not implemented in demo)
You can see the available UI for Traits here.
The REST API to access the properties contents is:
API usage examples examples:
Get default ordered properties for “i8n” set
Only get the “i8n/common.propeties”
Get the “i8n/common.propeties” followed by “i8n/welcomeEN.properties”
In addition, you can also list the contents in plain or JSon formats in case you need to use them in your own web page.
The REST API to navigate the properties is:
Where TYPE can be either “plain” or “json”.
For example, to list the properties files available on the “i8n” set simply point your browser to:
Specific Build projects
Now that we have the properties out of the way and loaded from a Properties Management System it would be nice to have specific builds of the main application generated from within their own maven projects. The following structure shows how this could be achieved.
Root pom.xml |-> EAR pom.xml |-> EJB pom.xml |-> WAR pom.xml |-> Builds (maybe with pom.xml for commonalities between application builds) |-> Specific Configuration pom.xml |-> Specific Configuration pom.xml
Basically a new area for specific builds related projects is added. The different Specific Configurations can and should make use of the Properties Management System in order to provide for content specific profiles.
Source code for Traits is available here. Like I said… the code is pretty ugly at this stage and no unit tests are included.
A Maven project example that makes use of the Traits PMS and the concepts explored in this post will soon be available in this section of the post.
P.S.: If you have ideas on how to make POMs files more readable and easier to maintain, please leave a note in the comments.