Ant with SCP

March 25th, 2007 6 Comments »

WOW! That was not easy to figure out. For the most part it was easy, but there was one bug that just hung me up for a while.

I laid out what we would need to do a remote deployment:

  1. Change web.xml so that it will work on the server.
  2. Build project.
  3. Change web.xml back so it is ready to work locally again.
  4. Copy war file to remote server.

There are two things to do to prepare for completing this.

  1. Get the ant library for the scp task downloaded and in place.
  2. Confirm environment variables are set.

So, to complete #1, download this file and save it to your ant installation’s lib directory. On my machine that was in C:\ant\lib, but yours may be different.

To complete #2, make sure your JAVA_HOME and ANT_HOME environment variables are set to the proper location. On my system JAVA_HOME = C:\Program Files\java\jdk1.5.0_11 and ANT_HOME = C:\ant.

To accomplish the first and third requirements, I added the following to the build.xml:

<property name="remoteLog4J" value="/"/>
<property name="localLog4J" value="/Users/nate/Documents/school/java/euphemia/src/config/log4j.properties"/>
<target name="prep-remote">
  <replaceregexp  file="${src}/web.xml" match="(&lt;param-name&gt;log4jProperties&lt;/param-name&gt;[^&lt;]*&lt;param-value&gt;)[^&lt;]+(&lt;/param-value&gt;)"
    replace="\1${remoteLog4J}\2"
    flags="g"
    />
  <echo>log4jProperties parameter value changed to ${remoteLog4J}</echo>
</target>
<target name="prep-local">
  <replaceregexp  file="${src}/web.xml" match="(&lt;param-name&gt;log4jProperties&lt;/param-name&gt;[^&lt;]*&lt;param-value&gt;)[^&lt;]+(&lt;/param-value&gt;)"
    replace="\1${localLog4J}\2"
    flags="g"
    />
  <echo>log4jProperties parameter value changed to ${localLog4J}</echo>
</target>

I allowed build to function normally, without change. Deployment is as follows:

<property name="remoteUser" value="nsutton"/>
<property name="remoteURI" value="cisjava2.matcmadison.edu"/>
<property name="remoteDeploymentDir" value="/home/nsutton/tomcat/webapps"/>
<property name="remoteDeploymentPath" value="${remoteUser}:${remote.password}@${remoteURI}:${remoteDeploymentDir}"/>
<target name="deploy-remote" depends="prep-remote,dist,prep-local">
  <scp trust="true" file="${dist}/euphemia.war" todir="${remoteDeploymentPath}"/>
</target>

To use the remote deployment:

ant deploy-remote -Dremote.password=MyPasswordHere

To customize this code for your use you will need to change the following properties:

  • remoteLog4J
  • localLog4J
  • remoteUser
  • remoteDeploymentDir

You will also need to change the name of your war file in the file attribute of the scp task in the deploy-remote target. Mine is euphemia.war, yours should be different. For that matter, I believe this should be in a property, but for the sake of keeping this post simple, I have kept it like this.

Here is my build.xml file.

I am COMPLETELY open to criticism/additions/fixes for this setup. I make no claim on it being a perfect solution and gladly welcome any and all input.

Javadoc and Ant

March 13th, 2007 7 Comments »

For Enterprise Java, we were challenged to get Ant to handle Javadocs for us. I set out to accomplish this, and did, so I thought I would share it with you.

In order to setup Ant to handle Javadocs, we need to setup targets and tasks. What are targets and tasks, you ask? To answer this, lets look at an example:

<target name="clean" description="clean up">
  <!-- Delete the ${build} and ${dist} directory trees -->
  <delete dir="${build}"/>
  <delete dir="${dist}"/>
</target>

When you are in the same directory as the build.xml file, you need only type the command ant clean to delete the build and dist directories. In this case the target is clean and the tasks are both delete tasks. In the same way, we use targets like build, deploy, and compile which each accomplish tasks which range from simple timestamps with tstamp to complex compilations with javac.

One other note about the previous section of code before we move onto adding Javadoc functionality. The delete tasks in that snippet make use of what Ant calls properties. Properties may look familiar to you if you have ever used JSTL, they behave similar to JSTL’s variables. In this case we are substituting the value of the build and dist properties into the dir attribute of the delete task. Why use properties for something so trivial? Imagine you hard-code the value of build into every task that requires the value. Now suppose you must change the value of this variable, what then? Search and replace sounds fine until you have overlapping values and replace what you hadn’t intended. Instead it is far easier to use a property and change the value in one place, easy to find, at the top of the document. The following is an example of setting properties:

<property name="build" value="build"/>
<property name="dist" value="dist"/>

So, now we consider how to make Ant handle Javadocs. Would it make sense to include it in the compile target for our project, or the build target? Do we really want to recompile Javadocs every time we build our project? We really only need to build it before each checkpoint to test that they compile properly. So, I made a target called jd. I called it jd because I am an extremely lazy typist, follow suit for less finger-tapping.

<target name="jd">
</target>

Ok, now the hard part is over…just kidding. We need to explore the tasks available to us and what to use for Javadocs. You can look at the tasks here under Ant Tasks > Core Tasks. The one we need to use is the aptly named Javadoc. This resource is extremely useful in determining the syntax to use. We can see what attributes are required and a description of them. For Javadoc we can see that we need to specify the location of the source files and the destination of the Javadocs. Lets do that, this is the outcome:

<property name="javadocs" value="docs/javadocs"/>
<target name="jd">
  <javadoc sourcepath="${src}" destdir="${javadocs}"/>
</target>

I chose to add a property for the Javadocs directory, which in the real build.xml would be located at the top of the document. I also chose to use the docs/javadocs to store the Javadoc output. Why? Because the docs directory is under version control and may eventually contain non-javadoc documentation which we may also want to keep in version control. By keeping Javadocs in their own directory we can then also clean them along with the build and dist directories. This is my new clean target:

<target name="clean" description="clean up">
  <!-- Delete the ${build}, ${dist}, and ${javadocs} directory trees -->
  <delete dir="${build}"/>
  <delete dir="${dist}"/>
  <delete dir="${javadocs}"/>
</target>

So, after doing this I went and tested the jd target…and…drumroll please…108 WARNINGS!? Confused and bewildered, I consulted a couple Java sources to find if this was normal. IT IS NOT. When digging through the warnings I noticed an issue cropping up over and over, and it wasn’t a problem with my code. It seemed as though Javadoc wouldn’t find the J2EE libraries/sources. Surely if we can compile then Java can find the libraries, right? Right, but the compile target specifies the location of the libraries using the extdirs attribute, and the Javadoc task happens to have the same attribute available for use. Here is my final jd target:

<property name="javadocs" value="docs/javadocs"/>
<target name="jd">
  <javadoc sourcepath="${src}" destdir="${javadocs}" extdirs="${lib}"/>
</target>

After adding this portion it all worked smoothly! And the people rejoiced! I’m attaching my final build.xml for checkpoint 2 for you to peruse!

Click here for my build.xml.