Faking Tomcat Support in IntelliJ IDEA Community Version

A while back, I blogged about my switch from Eclipse to the community (free) version of IntelliJ IDEA. After that, I went on a number of trips out of town, felt out the job market a bit, and generally engaged in a series of activities that have kept me too busy to work on my home automation. In the last week, however, that’s changed and I’ve revisited it.

The first thing that I decided to do was play with Ant a bit to create an environment where I could build and run the application locally. I’m in a bit of a catch-22 with IntelliJ at the moment. I might be interested in purchasing the Ultimate Edition, but not before I take it out for a few months and kick the tires. But, in order to do that without pain, I kind of need the server support for what I’m doing, which is only available in Ultimate. So, I’m faking it. I created the following Ant build.xml:

<?xml version="1.0" ?>
<project name="Daedalus" default="war">

    <path id="compile.classpath">
        <fileset dir="WebContent/WEB-INF/lib">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="init">
        <mkdir dir="build/classes"/>
        <mkdir dir="dist" />
    </target>

    <target name="compile" depends="init" >
        <javac destdir="build/classes" debug="true" srcdir="src">
            <classpath refid="compile.classpath"/>
        </javac>
    </target>

    <target name="war" depends="compile">
        <war destfile="C:\program files\Tomcat 6.0\webapps\Daedalus.war" webxml="WebContent/WEB-INF/web.xml">
            <fileset dir="WebContent"/>
            <fileset dir="src"/>
            <lib dir="WebContent/WEB-INF/lib"/>
            <classes dir="build/classes"/>
        </war>
        <exec executable="C:\program files\Tomcat 6.0\bin\startup.bat"/>
        <property name="browser" location="C:/Documents and Settings/Erik/Local Settings/Application Data/Google/Chrome/Application/chrome.exe"/>
        <exec executable="${browser}" spawn="true">
            <arg value="http://localhost:8080/Daedalus/"/>
        </exec>
    </target>

    <target name="clean">
        <delete dir="dist" />
        <delete dir="build" />
    </target>

</project>

The other build targets are somewhat standard, if memory serves (I was never particularly adept with Ant, and now I’m several years removed from using it). But, the interesting one is the “war” target, which I’m probably going to rename here shortly. This first compiles the project into a deployable WAR file and plops it into the local Tomcat webapps directory, which is where the it needs to be for me to run it locally in a browser.

With that in place, I’ve added the next line, which starts the web server. In the way I invoke it, a command window pops up, and I can stop the server by closing it. Once the server is started, I launch chrome to the URL where the application will be. This works, but I’d like to refine it a bit. Here are some things that I think should happen:

  1. First of all, DRY isn’t just for code. I’m defining “Daedalus.war” and “http://localhost:8080/Daedalus” and if I decide to change the deployable name, there are two failure points. I’m going to correct that.
  2. And, as long as I’m changing the “destfile” property of the war file, I might as well define a descriptive constant for the Tomcat webapps directory.
  3. Secondly, “browser” isn’t a particularly good property name for Chrome, so I’m going to rename it.
  4. Along those same lines, I’m going to create a property for Internet Explorer as well
  5. I’m also going to create build targets for chrome and internet explorer so that I can choose which one to run without modifying the build.xml file.
  6. Finally, I’m going to decouple the building of the War from the starting of the server and decouple both of those from opening a browser. That way I won’t have to repeat myself in the internet explorer and chrome versions.

Here’s what it looks like now:

<?xml version="1.0" ?>
<project name="Daedalus" default="runChrome">

    <property name="chrome" location="C:/Documents and Settings/Erik/Local Settings/Application Data/Google/Chrome/Application/chrome.exe"/>
    <property name="iexplorer" location="c:/Program Files/Internet Explorer/iexplore.exe"/>
    <property name="tomcatHome" location="C:/program files/Tomcat 6.0"/>
    <property name="webroot" location="${tomcatHome}/webapps"/>
    <property name="tomcatServerStart" location="${tomcatHome}/bin/startup.bat"/>
    <property name="localWebServer" location="http://localhost:8080"/>

    <property name="deploymentTargetName" value="Daedalus"/>

    <path id="compile.classpath">
        <fileset dir="WebContent/WEB-INF/lib">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="init">
        <mkdir dir="build/classes"/>
        <mkdir dir="dist" />
    </target>

    <target name="compile" depends="init" >
        <javac destdir="build/classes" debug="true" srcdir="src">
            <classpath refid="compile.classpath"/>
        </javac>
    </target>

    <target name="war" depends="compile">
        <war destfile="${webroot}\${deploymentTargetName}.war" webxml="WebContent/WEB-INF/web.xml">
            <fileset dir="WebContent"/>
            <fileset dir="src"/>
            <lib dir="WebContent/WEB-INF/lib"/>
            <classes dir="build/classes"/>
        </war>
    </target>

    <target name="startTomcat" depends="war">
        <exec executable="${tomcatServerStart}"/>
    </target>

    <target name="runChrome" depends="startTomcat">
        <exec executable="${chrome}" spawn="true">
            <arg value="http://localhost:8080/${deploymentTargetName}/"/>
        </exec>
    </target>

    <target name="runInternetExplorer" depends="startTomcat">
        <exec executable="${iexplorer}" spawn="true">
            <arg value="http://localhost:8080/${deploymentTargetName}/"/>
        </exec>
    </target>

    <target name="clean">
        <delete dir="dist" />
        <delete dir="build" />
    </target>

</project>

So, I’m relatively pleased with this for the time being. Two small caveats with this approach, though. The first is that I don’t really like duplicating the “http://localhost:8080″ as the server’s localhost, but I’m unlikely ever to change this, and if I abstract that out to a constant, it fails for some reason that I haven’t seriously looked into (and realistically, probably won’t for now). The second is that I start the server, but you have to manually stop it. That’s kind of ick, but I’ll live with it for now. If/when I put together a better scheme, I’ll post it.

But, with this you get support for Tomcat with IntelliJ IDEA community edition. It’s obviously not nearly as snazzy as having it integrated to the IDE, but if you’re in my boat, this is nice. I’ve automated most of the stuff that I’d rely on the IDE to do, and I’ve done it without spending a few hundred dollars I’m not yet sure I can justify. Cheers if this helps you.