<img height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=299788&amp;fmt=gif">

Streamlining Your Java Development Setup with the Tomcat Maven Plugin

Software Development, Software Solutions, Java

By Scott Smith

Tomcat Maven Plugin

I'm one of those people who feels that if there are more than 3 steps in setting up a project, there's more work to do. I remember one place I worked at started out with a one week setup period before you were expected to have the project up and running. It was an exceedingly complex J2EE project and included a 150 page setup document. I remember it had a pointless RMI server that had to be run along with an Oracle database and an unwieldy Ant script that only ran on one old version of Apache Ant. You would set up a full J2EE app server and it had to run part of the project with a JSP that had a bunch of scriptlets in it to generate more build artifacts to be reused in running the rest of the build. I'm probably forgetting a few things by now, but suffice it to say it was a total nightmare.

It also would only run under Eclipse with hard coded directory structures in a particular way. Debugging was finicky and JUnit tests were nonexistent. Everything was so tightly coupled that it was impossible to mock anything or break dependencies. The system couldn't be skinned or the presentation reformatted without breaking everything. Most of the pages had JSPs with scriptlets and the JSPs were nested 15 or more deep.
As form factors changed and web services emerged, nothing could be adjusted without complete breakage of the system. It was the most anti-agile project you'd ever seen. It was slow and bloated. It took 15 minutes on state of the art hardware to run the project to see if your code worked! Mistake? Fix and restart... 15 more minutes.


The project was too expensive to maintain and collapsed under its own technology weight. A story like this can go on and on but that's not the point here. Stories like this gave Java and J2EE a bad name.


Not long after that business collapsed, I started fresh on a new project for a startup. I like Java because it's fast, flexible and it scales. And there's a ton of great tooling to make large projects easy to manage. One of my favorites is the Tomcat Maven Plugin. So the steps in setting up a project boil down to:

  1. clone the project from the repository: git clone my-project
  2. build the project: mvn clean install
  3. run the project: mvn tomcat7:run

That's it. If your project requires more than this, you can do better... and you should. I'm assuming you have Java, Maven, any databases installed, etc. But you should because this isn't the first project you've done, right? I even had one project where we started up a Jetty instance to run a Solr server for search built right into the build!


We should Maven-ize everything? I've heard people make fun of this, but the answer is yes! Each IDE, be it Eclipse or any of its variants, Netbeans, Intellij, or anything else, has its own app server hooks with different quirks and different procedures for getting them set up. They also introduce variation in the setup. Different class loading, different configuration setups, and different debug settings. People have differing IDE preferences and learning a new one or using your least favorite one for a project just because it's set up that way is not maximizing the efficiency of your developers. And really, should your designers and front end developers really have to run, say Eclipse, just because of the app server or should they use the tools they like the most?


My philosophy is to let people use their most efficient tools to get the job done. Guys writing JavasScript should not be wasting time on setting up or rerunning a JEE environment. They ought to start the app server in one command and start coding. No barriers to getting work done.


I recently started working on a project that did not have this Tomcat Maven Plugin and Eclipse or STS was the "blessed" tool set. I'm not going to go into all the grumbling about Eclipse. I hate it. Period.


I had two major problems to overcome to make this work. First, it was a multi-module project. Second, it used several container managed data sources. I didn't know how to set this up and I found very little information on the Internet on how to do it.


First, I'll deal with the multi-module issue. The temptation is to put the configuration in the project's web module. That is the one that generates the WAR. But this is actually wrong because the Tomcat Maven Plugin might not necessarily see all the modules and then satisfy the dependencies, even if they are declared in the WAR generating module. What this means is all the configuration for the Tomcat Maven Plugin goes in the top level parent pom.


The first item of interest below is the usual Maven coordinates for the group ID, the artifact ID, and the version of the plugin. Below that is the configuration. The standard is port 8080, but that is specified here to illustrate. The most import sections are the CATALINA_OPTS that often have to be tweaked depending on your needs. What I've specified here is not important. It's just an example. You can use this to help see the format for your own needs. I also added a variation of the format for adding JVM parameters. You can use either format.


The next important tag is the context file you'd normally have in a Tomcat installation. That file is explained more below.


I've configured the path, that is the location you'd use to navigate with your browser's URL, to be the project's final build name in this case.


The last section is dependencies. These are dependencies that normally live on the classpath like JDBC database drivers. I've put in an example of MySQL, but anything can be added. These are normally dependencies that live in $TOMCAT_HOME/lib.

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <port>8080</port>
        <systemProperties>
            <CATALINA_OPTS>-Djava.awt.headless=true -Dfile.encoding=UTF-8
                            -server -Xms1536m -Xmx1536m
                            -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m
                            -XX:MaxPermSize=512m -XX:+DisableExplicitGC
                            -XX:+UseConcMarkSweepGC
                            -XX:+CMSIncrementalMode
                            -XX:+CMSIncrementalPacing
                            -XX:CMSIncrementalDutyCycleMin=0
                            -XX:-TraceClassUnloading
            </CATALINA_OPTS>
            <!--The way this would look as a JVM parameter on the tomcat server's
            catalina.sh is -Dspring.profiles.default=grid or -Dspring.profiles.active=local -->
            <spring.profiles.active>local</spring.profiles.active>
            <spring.profiles.default>grid</spring.profiles.default>
        </systemProperties>
        <contextFile>${basedir}/src/test/resources/maven-tomcat-plugin/context.xml</contextFile>
        <path>/${project.build.finalName}</path>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.14</version>
        </dependency>
    </dependencies>
</plugin>
Now, I'll deal with the data sources. This is something that I had a very hard time figuring out. If the project doesn't manage its own data sources or pooling with C3PO or something like that, then it is probably using container managed data sources. This is pretty simple to set up but there's not a lot of information out there about it. In the configuration above is a reference to a context.xml file. Sometimes data sources are configured in the server.xml, but they need to be moved to the context.xml. Below is an example of a configuration. Edit for your own project from this example.
<?xml version='1.0' encoding='utf-8'?>
<!-- The contents of this file will be loaded for each web application -->
<Context>
    <!-- Default set of monitored resources -->     <WatchedResource<WEB-INF/web.xml</WatchedResource>     <ResourceLink global="jdbc/data_source_1" name="data_source_1" type="javax.sql.DataSource" />     <ResourceLink global="jdbc/data_source_2" name="data_source_2" type="javax.sql.DataSource" />     <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver"               factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" logAbandoned="true" maxActive="75"               maxIdle="10" maxWait="10000" name="jdbc/data_source_1" password="password1" removeAbandoned="true"               removeAbandonedTimeout="60" scope="Shareable" type="javax.sql.DataSource"               url="jdbc:mysql://localhost:3306/data_source_1?autoReconnect=true" username="data_source_1_username" validationQuery="SELECT 1"               testOnBorrow="true"/>     <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver"               factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" logAbandoned="true" maxActive="75"               maxIdle="10" maxWait="10000" name="jdbc/data_source_2" password="password2" removeAbandoned="true"               removeAbandonedTimeout="60" scope="Shareable" type="javax.sql.DataSource"               url="jdbc:mysql://another_mysql_host:3306/data_source_2?autoReconnect=true" username="data_source_1_username"               validationQuery="SELECT 1" testOnBorrow="true"/>         </Context>
What's interesting about something like this is you can share the configuration in version control in your project without shipping items that are only needed for development or running this plugin. I've stuffed the context.xml here: ${basedir}/src/test/resources/maven-tomcat-plugin/context.xml. It's in the Maven project test area and won't end up in the final generated war for the project.
With this plugin, I achieved my goals of shared configuration via the repository with no set up. IDE independence. Hot editing of JSPs for speedy front end development. No extra configuration to debug within any IDE. A developer can set up a project and run the app server in the time it takes to clone, build, and run the tomcat server, taking no time out to configure aside from installing a database and setting that up for your needs. Java development really couldn't be any easier or more streamlined.

TAGS: Software Development, Software Solutions, Java

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Subscribe to Our Newsletter

Recent Blog Posts