; last updated - 8 minutes read

Introduction

Java developers must be patient. Even incredibly so. Mind you, back in the mid-90s IBM invented Hot Code Replacement to hide how slow their WebSphere Application Server was at the time. It took several minutes to start the application server and to deploy an application. This resulted in very slow turn-around cycles. In other words: developers spent a lot of time with waiting. Luckily IBM implemented Hot Code Replacement

in their JDK 1.3 virtual machine (IBM J9 VM), eliminating the nasty waits almost completely. It was an awesome experience at the time. When Hot Code Replacement later was introduced to SUN's JDK 1.4.1, we were very quick to adopt it. And today? By default, both Eclipse and Tomcat are configured such that every change of the source code results in reloading the context, which is just another word for restarting the application. Depending on the application, this is just a matter of seconds. It also may take a few minutes if you're working on a bigger application. In most cases, your application state is lost. You have to sign on again and to dig all the way through the seven pages of the wizard you're working on. Did I mention the error you're hunting occurs in wizard's last step?

What about you?

It doesn't have to be so. I'll show you some ways to get rid of the waits in a second. But before that, I'd like to ask you how you cope with deployment waits? Feel free to leave a comment if you're as impatient as I am. Or if you're just happy with you IDE even if it's a little slow at times. I've been asking a lot of people, and most of them didn't even understand my question. This even applies to Liferay developers. Those guys are suffering a lot more than the average developer: the server takes roughly a minute to start, and deploying a portlet typically takes 30 seconds. A colleague of mine had been working on a really big portlet, so he had to wait two or three minutes even if he had corrected merely a typo.

How to get rid of lengthy deployment and server start times

Over the years, I've tried four ways to optimize the turnaround cycle. I guess you'll like the last recipe best - it requires very little changes to the development process you're probably used to. However, if you're ready to modify your project's structure, I highly recommend recipe 2 or 3.

Recipe #1: Buy a commercial solution such as JRebel

These days it seems to be virtually every manager's first reaction to buy a solution (even prior to just sit down for five minutes and ponder about the problem at hand). Actually, there's a commercial solution, and as far as I know, it's pretty good one. JRebel takes Hot Code Replacement to another level. For instance, Hot Code Replacement always fails when you add a method or change its signature. JRebel is said to deal with such situations. Unfortunately, I failed to configure it correctly when I tried it with Liferay. I still believe it's a good solution, but it took me a day to fix my environment. So I never dared to try again. But it's still on the top of the tasks I want to do one day.

Recipe #2: Put your development file into Tomcat's webapp folder

This is the most radical recipe, and it works like charm. Don't bother with Eclipse's server configuration, remote debugging and stuff like that. Just install Tomcat, create your application folder as a subfolder of Tomcat's webapp folder, and put your application files into this subfolder - including your java source code. After that just configure your IDE to start Tomcat in debug mode. To find out the configuration, you have to open Tomcat's bin folder. If you haven't done this before, the next few lines may look a bit technical. But it's very simple, and you have to do this only once. And in case you really don't like the approach, feel free to jump to the next approach. Edit the file

catalina.bat, roughly at line 290 (as for Apache Tomcat 7). Those lines are very long, but don't let them deter you: it's really simple. All you have to do is to copy the line starting with

EXECJAVA, put an

ECHO command in front of the first copy and a

PAUSE command behind it. To make things confusing,

catalina.bat contains four lines starting with

EXECJAVA. It suffices to copy and echo the first on. The resulting code should look like so:


if not "%JPDA%" == "" goto doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity echo %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% pause %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%

As mentioned above, line 3 is a copy of line 5 with a preceding

ECHO command. Now you start Tomcat by double-clicking

startup.bat. Before starting (remember the

PAUSE command) Tomcat shows a Windows command window containing the informations you need.


start "Tomcat" "C:\Program Files\Java\jdk1.6.0_22\bin\java" -Djava.util.logging.config.file="D:\eclipse\Tomcat7\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs="D:\eclipse\Tomcat7\endorsed" -Dcatalina.base="D:\eclipse\Tomcat7" -Dcatalina.home="D:\eclipse\Tomcat7" -Djava.io.tmpdir="D:\eclipse\Tomcat7\temp" -classpath "D:\eclipse\Tomcat7\bin\bootstrap.jar;D:\eclipse\Tomcat7\bin\tomcat-juli.jar" org.apache.catalina.startup.Bootstrap start

The -D parameters have to be put into the be "VM arguments" field of Eclipse's "Debug configurations" dialog. "start" is a regular argument. You have to add the files

bootstrap.jar and

tomcat-juli.jar to the class path, as well as your applications jar.

(click to enlarge)

Disadvantages of the Tomcat approach

I've been embedding my source code into Tomcat for many years, and I only found two disadvantages:

  • You have to obey to Tomcat's ideas of where to put files. Put HTML files into the root directory, libraries have to be put into WEB-INF/lib and classes have to be put into WEB-INF/classes. Source codes are best put into WEB-INF/src. This isn't much of a problem - unless you use a tool like Maven or Gradle. Both tools can be configured to serve Tomcat's structure, but this requires additional configuration. More important, to many people the primary reason to use Maven is the predefined folder structure.
  • If you don't use Tomcat, but another application server such as JBoss, WebSphere or Liferay, my approach means a lot of work - if it's possible at all.

Recipe #3: Use Jetty as an embedded server

Jetty is an alternative to Tomcat. One of the most interesting features of Jetty is the ability to use it as an embedded server. Instead of starting the application as part of the application server, you start the application server as part of the application. This requires merely 20 lines of code. The advantage of embedded Jetty are super-fast start-up times, typically less than a second. The disadvantages are the predefined folder structure (which is different from Maven's ideas of how to organize source code) and not being able to use Tomcat's configuration files. Probably there's a way to configure global environment variables, but if I'm not mistaken, it's not done by editing

context.xml and

server.xml - at least not in embedded mode. Another disadvantage of the embedded mode is you can embed only one application. However, this shouldn't be a problem during development time.

Recipe #3+: Use SWT's browser widget

While you're at embedding the server, you can also embed the client. Most of the time you don't need the power of a full-blown browser. SWT offers a nice browser component. You can use it to open a window with a predefined URL immediately after starting Jetty. I've been using this recipe for a couple of years. It's a lot of fun. It's extremely efficient programming. Your boss will love it very much. However, I abandoned the Jetty recipe the day I was asked to write Liferay portlets. It felt like being expulsed from paradise, so I'm still looking for ways to optimize the deployment process.

Recipe #4: Use the FileSync Eclipse plugin

Andrey Loskutov wrote a nice little plugin dedicated to synchronizing folders. Every time you change a file in Eclipse the file is copied to another location. That's exactly what we need. To utilize FileSync, find out where Eclipse deploys your application. Maven users have to define a couple of synchronization rules. The plugin's GUI isn't perfect, so maybe you have to edit its configuration file manually. It's located in the .settings folder of your project. I put a very simple configuration file at Angular Faces' GitHub repository. To prevent Tomcat from reloading the application (aka "context") every time FileSync has activated a file, add a context.xml entry to prevent this.

In production the

reloadable flag is probably disabled anyways, so this setting won't hurt anybody. By default, Eclipse is configured to publish changes very often. If you're using FileSync, you can switch this feature off:

Conclusion

Currently, I'm using the last recipe to optimize my deployment process. What puzzles me is that I have met hardly anybody taking pains the get rid of the deployment times. Even Wikipedia hardly mentions Hot Code Replacements. The wait drives me nuts, so I consider this very astonishing. What about you? Do the deployment delays bother you, or is it just the way it is? I'd like to read your comments!


Comments