After spending more time than I care to indulge trying to get commercial application servers to behave, I finally decided to Do the Simplest Thing that Could Possibly Work, and create a new application server from scratch. Well, not really a full application server. For 90 % of the Java applications out there, all that you really need is Servlets, so I limit myself to that. And not really from scratch. The servlet functionality is provided by jetty, the application is built using Maven, the startup script is generated with the Maven Appassembler Plugin, and the final package is constructed using Maven Assembly Plugin.
The result is a project that lets me construct and release zip-files that can be copied onto an server host, extracted, and started up with a single script. With some help from my friends, I’ve added a few bells and whistles to make it as complete as possible. However, this article describes the simplest possible “Maven application server” that you can start with. You can find the application code in my subversion repository.
The life-cycle of application development
My main rationale for creating the Maven Application Server was to take control of my whole application development life-cycle. Most application server vendors consider the whole lifespan from test to production too naïvely. Here is what I want to do:
- I find a new requirement or bug, that requires me to change the code.
- First, I implement a test for the change in my IDE. This is done by checking out the main trunk from subversion and executing
mvn eclipse:eclipse -DdownloadSources=truein the top level directory. I can then import the files and work with them as normal.
- Second, I want to make sure that the web module runs correctly. As per my article on the subject, I have created a unit tests that fires up an Jetty instance and tests that it can access the web application. I have also created a Main Class, which can be started under the IDE debugger. This way, I can quickly debug the problem if my test fails.
- When I’m satisfied, I run
mvn deployon the top level directory. This pushes out a new snapshot version of the whole application to a maven repository (the example uses a local disk for illustration purposes). This ZIP-file can be downloaded to the workstation of a tester. The tester extracts the file and double clicks the start script that was generated by the appassembly plugin. The tester can then check the functionality more throughly (try downloading the zip file, unzip it and double-click the reference-app.bat script, and go to http://localhost:9090/reference-web/). We have also created scripts that automatically pull down the latest version to integration test servers as part of our automated build.
- When we’re happy with the version, we can use
mvn release:performto construct a released version. This tags the code in svn and pushes out a final version of the zip file to the Maven repository.
- We then typically use scripts on the staging environment to pull down the released version from the Maven repository. If everything works there, we pull down and start the server on the production environment.
- This completes one development cycle.
Some work left for the reader (or a later article)
The use of the appassembler plugin is currently a bit rough. However, Trygve and Kristian, the developers of the plugin have a version in the works that will fix my needs.
Deploying and installing new versions of the ZIP on a server requires a little script. I might post the details on how we set this up in a later entry. Our deployment strategy separates the configuration settings from the software, so we can upgrade the application without having to mess around with the settings. We can also deploy several version on the same host, each having separate settings.
The use of Jetty should be expanded to be more sophisticated than my current toy example. You will need to read configuration for things like port numbers and possibly database settings. You might also want to implement functionality for shutting the server down.
By taking responsibility of the application server, we have regained control over the whole software development life cycle. This enables us to eliminate a few of our configuration management issues, and close the loop from unit testing to production.
As an added bonus, we have been able to construct the whole solution using only open source components. This both reduce the work we have to do, and our licensing expenses. I would especially like to thank Trygve and Kristian, who’ve created the critical piece to make the whole puzzle fit together.